<!DOCTYPE html>
<html lang="en"><head>
    <title>CZH-DEV BLOG</title>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    <meta content="utf-8" http-equiv="encoding">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="format-detection" content="telephone=no" />
    <meta name="theme-color" content="#000084" />
    <link rel="icon" href="https://czh-dev.gitee.io/czh-blog.gitee.io//favicon.ico">
    <link rel="canonical" href="https://czh-dev.gitee.io/czh-blog.gitee.io/">
    
    
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="navbar-inner">
        <div class="container">
            <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"></button>
            <a class="brand" href="https://czh-dev.gitee.io/czh-blog.gitee.io/">CZH-DEV BLOG</a>
            <div class="nav-collapse collapse">
                <ul class="nav">
                    
                    
                        
                            <li>
                                <a href="/czh-blog.gitee.io/about/">
                                    
                                    <span>About</span>
                                </a>
                            </li>
                        
                    
                        
                            <li>
                                <a href="/czh-blog.gitee.io/post/">
                                    
                                    <span>All posts</span>
                                </a>
                            </li>
                        
                    
                        
                            <li>
                                <a href="/czh-blog.gitee.io/ebook/">
                                    
                                    <span>Resource</span>
                                </a>
                            </li>
                        
                    
                </ul>
            </div>
        </div>
    </div>
</nav><div id="content" class="container">
<div style="display: flex;">
  <div class="row-fluid navmargin">
    <div class="page-header">
      <h1>Spring Cloud Alibaba（全） - Sat, Feb 11, 2023</h1>
    </div>
    <p class="lead"></p>
    <h1 id="第一章-微服务概念">第一章 微服务概念</h1>
<h2 id="11-单体分布式集群">1.1 单体、分布式、集群</h2>
<p>我们学习微服务之前,需要先理解单体、集群、分布式这些概念，这样会帮助我们在学习 后面课程会更加容易些.</p>
<p><strong>单体</strong></p>
<p>一个系统业务量很小的时候所有的代码都放在一个项目中就好了，然后这个项目部署在一台服务器上就好了。整个项目所有的服务都由这台服务器提供。这就是单机结构。</p>
<p><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111452238.png" alt="image-20201027172014044"></p>
<p>单体应用开发简单,部署测试简单.但是存在一些问题,比如:单点问题,单机处理能力有限,当你的业务增长到一定程度的时候，单机的硬件资源将无法满足你的业务需求。</p>
<p><strong>分布式</strong></p>
<p>由于整个系统运行需要使用到Tomcat和MySQL，单台服务器处理的能力有限,2G的内存需要分配给Tomcat和MySQL使用，，随着业务越来越复杂，请求越来越多. 内存越来越不够用了，所以这时候我们就需要进行分布式的部署.</p>
<p><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111452612.png" alt="image-20201027173909529"></p>
<p>我们进行一个评论的请求，这个请求是需要依赖<strong>分布</strong>在两台不同的服务器的组件[Tomat和MySQL],才能完成的. 所以叫做分布式的系统.</p>
<p><strong>集群</strong></p>
<p>在上面的图解中其实是存在问题的，比如Tomcat存在单点故障问题，一旦Tomcat所在的服务器宕机不可用了，我们就无法提供服务了,所以针对单点故障问题，我们会使用集群来解决.那什么是集群模式呢?</p>
<p>单机处理到达瓶颈的时候，你就把单机复制几份，这样就构成了一个“集群”。集群中每台服务器就叫做这个集群的一个“节点”，所有节点构成了一个集群。每个节点都提供相同的服务，那么这样系统的处理能力就相当于提升了好几倍（有几个节点就相当于提升了这么多倍）。</p>
<p>但问题是用户的请求究竟由哪个节点来处理呢？最好能够让此时此刻负载较小的节点来处理，这样使得每个节点的压力都比较平均。要实现这个功能，就需要在所有节点之前增加一个“调度者”的角色，用户的所有请求都先交给它，然后它根据当前所有节点的负载情况，决定将这个请求交给哪个节点处理。这个“调度者”有个牛逼了名字——负载均衡服务器。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111452503.png" alt="image-20201027182534219"></strong></p>
<p>我们在上面的图中仅展示了Tomcat的集群，如果MySQL压力比较大的情况下，我们也是可以对MySQL进行集群的.</p>
<h2 id="12-系统架构演变">1.2 系统架构演变</h2>
<p>​	随着互联网的发展，网站应用的规模也不断的扩大，进而导致系统架构也在不断的变化。</p>
<p>从互联网早起到现在，系统架构大体经历了下面几个过程: 单体应用架构&mdash;&gt;垂直应用架构&mdash;&gt;分布</p>
<p>式架构&mdash;&gt;SOA架构&mdash;&gt;微服务架构。</p>
<p>接下来我们就来了解一下每种系统架构是什么样子的， 以及各有什么优缺点。</p>
<h3 id="121-单体应用架构">1.2.1 单体应用架构</h3>
<p>​    互联网早期，一般的网站应用流量较小，只需一个应用，将所有功能代码都部署在一起就可以，这</p>
<p>样可以减少开发、部署和维护的成本。</p>
<p>​    比如说一个电商系统，里面会包含很多用户管理，商品管理，订单管理，物流管理等等很多模块，</p>
<p>我们会把它们做成一个web项目，然后部署到一台tomcat服务器上。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111452841.png" alt="image-20201028094613926"></strong></p>
<p><strong>优点：</strong></p>
<ul>
<li>
<p>项目架构简单，小型项目的话， 开发成本低</p>
</li>
<li>
<p>项目部署在一个节点上， 维护方便</p>
</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li>
<p>全部功能集成在一个工程中，对于大型项目来讲不易开发和维护</p>
</li>
<li>
<p>项目模块之间紧密耦合，单点容错率低</p>
</li>
<li>
<p>无法针对不同模块进行针对性优化和水平扩展</p>
</li>
</ul>
<h3 id="122-垂直应用架构">1.2.2 垂直应用架构</h3>
<p>​    随着访问量的逐渐增大，单一应用只能依靠增加节点来应对，但是这时候会发现并不是所有的模块</p>
<p>都会有比较大的访问量.</p>
<p>​    还是以上面的电商为例子， 用户访问量的增加可能影响的只是用户和订单模块， 但是对消息模块</p>
<p>的影响就比较小. 那么此时我们希望只多增加几个订单模块， 而不增加消息模块. 此时单体应用就做不</p>
<p>到了， 垂直应用就应运而生了.</p>
<p>​    所谓的垂直应用架构，就是将原来的一个应用拆成互不相干的几个应用，以提升效率。比如我们可</p>
<p>以将上面电商的单体应用拆分成:</p>
<ul>
<li>
<p>电商系统(用户管理 商品管理 订单管理)</p>
</li>
<li>
<p>后台系统(用户管理 订单管理 客户管理)</p>
</li>
<li>
<p>CMS系统(广告管理 营销管理)</p>
</li>
</ul>
<p>这样拆分完毕之后，一旦用户访问量变大，只需要增加电商系统的节点就可以了，而无需增加后台</p>
<p>和CMS的节点。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111453298.png" alt="image-20201028095743602"></strong></p>
<p><strong>优点：</strong></p>
<ul>
<li>
<p>系统拆分实现了流量分担，解决了并发问题，而且可以针对不同模块进行优化和水平扩展</p>
</li>
<li>
<p>一个系统的问题不会影响到其他系统，提高容错率</p>
</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li>
<p>系统之间相互独立， 无法进行相互调用</p>
</li>
<li>
<p>系统之间相互独立， 会有重复的开发任务</p>
</li>
</ul>
<h3 id="123-分布式架构">1.2.3 分布式架构</h3>
<p>​    当垂直应用越来越多，重复的业务代码就会越来越多。这时候，我们就思考可不可以将重复的代码</p>
<p>抽取出来，做成统一的业务层作为独立的服务，然后由前端控制层调用不同的业务层服务呢？</p>
<p>​    这就产生了新的分布式系统架构。它将把工程拆分成表现层和服务层两个部分，服务层中包含业务</p>
<p>逻辑。表现层只需要处理和页面的交互，业务逻辑都是调用服务层的服务来实现。</p>
<p><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111453205.png" alt="image-20201028103739904"></p>
<p><strong>优点</strong>：</p>
<ul>
<li>抽取公共的功能为服务层，提高代码复用性</li>
</ul>
<p><strong>缺点</strong>：</p>
<ul>
<li>系统间耦合度变高，调用关系错综复杂，难以维护</li>
</ul>
<h3 id="124-soa架构">1.2.4 SOA架构</h3>
<p>​    在分布式架构下，当服务越来越多，容量的评估，小服务资源的浪费等问题逐渐显现，此时需增加</p>
<p>一个调度中心对集群进行实时管理。此时，用于资源调度和治理中心(SOA Service Oriented</p>
<p>Architecture，面向服务的架构)是关键。</p>
<p><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111453137.jpg" alt="****"></p>
<p><strong>优点</strong>:</p>
<ul>
<li>使用注册中心解决了服务间调用关系的自动调节</li>
</ul>
<p><strong>缺点</strong>:</p>
<ul>
<li>
<p>服务间会有依赖关系，一旦某个环节出错会影响较大( 服务雪崩 )</p>
</li>
<li>
<p>服务关系复杂，运维、测试部署困难</p>
</li>
</ul>
<h3 id="125-微服务架构">1.2.5 微服务架构</h3>
<p>微服务架构在某种程度上是面向服务的架构SOA继续发展的下一步，它更加强调服务的&quot;彻底拆分&quot;。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111453027.png" alt="image-20201028110735067"></strong></p>
<p><strong>优点</strong>：</p>
<ul>
<li>
<p>服务原子化拆分，独立打包、部署和升级，保证每个微服务清晰的任务划分，利于扩展</p>
</li>
<li>
<p>微服务之间采用RESTful等轻量级Http协议相互调用</p>
</li>
</ul>
<p><strong>缺点</strong>：</p>
<ul>
<li>分布式系统开发的技术成本高（容错、分布式事务等）</li>
</ul>
<h2 id="13-微服务架构介绍">1.3 微服务架构介绍</h2>
<p>​    微服务架构， 简单的说就是将单体应用进一步拆分，拆分成更小的服务，每个服务都是一个可以独</p>
<p>立运行的项目。</p>
<p><strong>微服务架构的常见问题</strong></p>
<p>一旦采用微服务系统架构，就势必会遇到这样几个问题：</p>
<ul>
<li>
<p>这么多小服务，如何管理他们？</p>
</li>
<li>
<p>这么多小服务，他们之间如何通讯？</p>
</li>
<li>
<p>这么多小服务，客户端怎么访问他们？</p>
</li>
<li>
<p>这么多小服务，一旦出现问题了，应该如何自处理？</p>
</li>
<li>
<p>这么多小服务，一旦出现问题了，应该如何排错?</p>
</li>
</ul>
<p>对于上面的问题，是任何一个微服务设计者都不能绕过去的，因此大部分的微服务产品都针对每一</p>
<p>个问题提供了相应的组件来解决它们。</p>
<p><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111453414.jpg" alt="****"></p>
<h2 id="14-springcloud介绍">1.4 SpringCloud介绍</h2>
<p>Spring Cloud是一系列框架的集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发，如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等，都可以用Spring Boot的开发风格做到一键启动和部署。</p>
<p>Spring Cloud并没有重复制造轮子，它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来，通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理，最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。</p>
<h3 id="141-springboot和springcloud有啥关系">1.4.1 SpringBoot和SpringCloud有啥关系?</h3>
<ul>
<li>
<p>SpringBoot专注于快速方便的开发单个个体微服务。</p>
</li>
<li>
<p>SpringCloud是关注全局的微服务协调整理治理框架，它将SpringBoot开发的一个个单体微服务整合并管理起来，为各个微服务之间提供，配置管理、服务发现、断路器、路由、事件总线、分布式事务、等等集成服务。</p>
</li>
</ul>
<p><strong>总结</strong>: SpringBoot专注于快速、方便的开发单个微服务个体，SpringCloud关注全局的服务治理组件的集合。</p>
<h3 id="142-springcloud版本名称">1.4.2 SpringCloud版本名称?</h3>
<p>因为Spring Cloud不同其他独立项目，它是拥有很多子项目的大项目。所以它是的版本是 版本名+版本号 （如Greenwich.SR6）。
版本名：是伦敦的地铁名
版本号：SR（Service Releases）是固定的 ,大概意思是稳定版本。后面会有一个递增的数字。
所以 Greenwich.SR6就是Greenwich的第6个Release版本。</p>
<h3 id="143-为什么选择springcloud-alibaba">1.4.3 为什么选择SpringCloud Alibaba？</h3>
<p>我们这里为什么选择SpringCloud Alibaba呢，主要因为SpringCloud Netflix的组件：服务注册与发现的 Eureka、服务限流降级的 Hystrix、网关 Zuul都已经停止更新了，当然继续使用是没问题的，只是出现问题，官方不维护，需要自行解决.</p>
<h1 id="第二章-微服务环境搭建">第二章 微服务环境搭建</h1>
<p>我们在讲解SpringCloud的课程中，使用简单易懂的模块给同学讲解里面相关的组件.</p>
<p><strong>商品微服务</strong></p>
<ul>
<li>查询商品列表</li>
</ul>
<p><strong>订单微服务</strong></p>
<ul>
<li>创建订单</li>
</ul>
<h2 id="21-技术选型">2.1 技术选型</h2>
<p>持久层:  SpingData Jpa</p>
<p>数据库: MySQL5.7</p>
<p>其他: SpringCloud Alibaba 技术栈</p>
<h2 id="22-模块设计">2.2 模块设计</h2>
<p>&mdash; shop-parent 父工程</p>
<p>​     &mdash; shop-product-api 商品微服务api 【存放商品实体】</p>
<p>​     &mdash; shop-product-server 商品微服务 【端口:808x】</p>
<p>​     &mdash; shop-order-api 订单微服务api 【存放订单实体】</p>
<p>​     &mdash; shop-order-server 订单微服务 【端口:809x】</p>
<h2 id="23-微服务调用">2.3 微服务调用</h2>
<p>​    在微服务架构中，最常见的场景就是微服务之间的相互调用。我们以电商系统中常见的<strong>用户下单</strong>为</p>
<p>例来演示微服务的调用：客户向订单微服务发起一个下单的请求，在进行保存订单之前需要调用商品微</p>
<p>服务查询商品的信息。</p>
<p>我们一般把服务的主动调用方称为<strong>服务消费者</strong>，把服务的被调用方称为<strong>服务提供者</strong>。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111453819.png" alt="image-20201028144911439"></strong></p>
<p>在这种场景下，订单微服务就是一个服务消费者， 商品微服务就是一个服务提供者。</p>
<h2 id="24-版本说明">2.4 版本说明</h2>
<p>​	https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111453842.png" alt="image-20201028150721156"></strong></p>
<h2 id="25-创建父工程">2.5 创建父工程</h2>
<p>创建一个maven工程，然后在pom.xml文件中添加下面内容</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#75715e">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;project</span> <span style="color:#a6e22e">xmlns=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xmlns:xsi=</span><span style="color:#e6db74">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xsi:schemaLocation=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;modelVersion&gt;</span>4.0.0<span style="color:#f92672">&lt;/modelVersion&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;groupId&gt;</span>cn.czh0123<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;artifactId&gt;</span>shop-parent<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;version&gt;</span>1.0.0<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;packaging&gt;</span>pom<span style="color:#f92672">&lt;/packaging&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">&lt;!--父工程--&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;parent&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;groupId&gt;</span>org.springframework.boot<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;artifactId&gt;</span>spring-boot-starter-parent<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;version&gt;</span>2.3.2.RELEASE<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/parent&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">&lt;!--依赖版本的锁定--&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;properties&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;java.version&gt;</span>1.8<span style="color:#f92672">&lt;/java.version&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;project.build.sourceEncoding&gt;</span>UTF-8<span style="color:#f92672">&lt;/project.build.sourceEncoding&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;project.reporting.outputEncoding&gt;</span>UTF-8<span style="color:#f92672">&lt;/project.reporting.outputEncoding&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;spring-cloud.version&gt;</span>Hoxton.SR8<span style="color:#f92672">&lt;/spring-cloud.version&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;spring-cloud-alibaba.version&gt;</span>2.2.3.RELEASE<span style="color:#f92672">&lt;/spring-cloud-alibaba.version&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/properties&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;dependencyManagement&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependencies&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">&lt;groupId&gt;</span>org.springframework.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-dependencies<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">&lt;version&gt;</span>${spring-cloud.version}<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">&lt;type&gt;</span>pom<span style="color:#f92672">&lt;/type&gt;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">&lt;scope&gt;</span>import<span style="color:#f92672">&lt;/scope&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">&lt;groupId&gt;</span>com.alibaba.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-alibaba-dependencies<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">&lt;version&gt;</span>${spring-cloud-alibaba.version}<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">&lt;type&gt;</span>pom<span style="color:#f92672">&lt;/type&gt;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">&lt;scope&gt;</span>import<span style="color:#f92672">&lt;/scope&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependencies&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/dependencyManagement&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/project&gt;</span>
</span></span></code></pre></div><h2 id="26-创建商品微服务">2.6 创建商品微服务</h2>
<p>1.创建shop-product-api项目，然后在pom.xml文件中添加下面内容</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#75715e">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;project</span> <span style="color:#a6e22e">xmlns=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xmlns:xsi=</span><span style="color:#e6db74">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xsi:schemaLocation=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;parent&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;artifactId&gt;</span>shop-parent<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;groupId&gt;</span>cn.czh0123<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;version&gt;</span>1.0.0<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/parent&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;modelVersion&gt;</span>4.0.0<span style="color:#f92672">&lt;/modelVersion&gt;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;artifactId&gt;</span>shop-product-api<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">&lt;!--依赖--&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;dependencies&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>org.springframework.boot<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>spring-boot-starter-data-jpa<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>org.projectlombok<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>lombok<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/dependencies&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/project&gt;</span>
</span></span></code></pre></div><p>2 创建实体类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//商品
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">@Entity</span><span style="color:#f92672">(</span>name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;t_shop_product&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Data</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Product</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Id</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@GeneratedValue</span><span style="color:#f92672">(</span>strategy <span style="color:#f92672">=</span> GenerationType<span style="color:#f92672">.</span><span style="color:#a6e22e">IDENTITY</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Long pid<span style="color:#f92672">;</span><span style="color:#75715e">//主键
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> String pname<span style="color:#f92672">;</span><span style="color:#75715e">//商品名称
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> Double pprice<span style="color:#f92672">;</span><span style="color:#75715e">//商品价格
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> Integer stock<span style="color:#f92672">;</span><span style="color:#75715e">//库存
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>3.创建shop-product-server项目，然后在pom.xml文件中添加下面内容</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#75715e">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;project</span> <span style="color:#a6e22e">xmlns=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xmlns:xsi=</span><span style="color:#e6db74">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xsi:schemaLocation=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;parent&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;artifactId&gt;</span>shop-parent<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;groupId&gt;</span>cn.czh0123<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;version&gt;</span>1.0.0<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/parent&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;modelVersion&gt;</span>4.0.0<span style="color:#f92672">&lt;/modelVersion&gt;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;artifactId&gt;</span>shop-product-server<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;dependencies&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>org.springframework.boot<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>spring-boot-starter-web<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>mysql<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>mysql-connector-java<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>com.alibaba<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>fastjson<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;version&gt;</span>1.2.56<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>cn.czh0123<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>shop-product-api<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;version&gt;</span>1.0.0<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/dependencies&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/project&gt;</span>
</span></span></code></pre></div><p>4.编写启动类ProductServer.java</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@SpringBootApplication</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ProductServer</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        SpringApplication<span style="color:#f92672">.</span><span style="color:#a6e22e">run</span><span style="color:#f92672">(</span>ProductServer<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">,</span>args<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>5.编写配置文件application.yml</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">server</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">port</span>: <span style="color:#ae81ff">8081</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">application</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">product-service</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">datasource</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">driver-class-name</span>: <span style="color:#ae81ff">com.mysql.jdbc.Driver</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">url</span>: <span style="color:#ae81ff">jdbc:mysql:///shop-product?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">username</span>: <span style="color:#ae81ff">root</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">password</span>: <span style="color:#ae81ff">admin</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">jpa</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">properties</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">hibernate</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">hbm2ddl</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">auto</span>: <span style="color:#ae81ff">update</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">dialect</span>: <span style="color:#ae81ff">org.hibernate.dialect.MySQL5InnoDBDialect</span>
</span></span></code></pre></div><p>6.在数据库中创建shop-product的数据库</p>
<p>7.创建ProductDao</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.dao<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">ProductDao</span> <span style="color:#66d9ef">extends</span> JpaRepository<span style="color:#f92672">&lt;</span>Product<span style="color:#f92672">,</span> Long<span style="color:#f92672">&gt;</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>8.创建ProductService接口和实现类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.service.impl<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Service</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ProductServiceImpl</span> <span style="color:#66d9ef">implements</span> ProductService <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> ProductDao productDao<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Product <span style="color:#a6e22e">findByPid</span><span style="color:#f92672">(</span>Long pid<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> productDao<span style="color:#f92672">.</span><span style="color:#a6e22e">findById</span><span style="color:#f92672">(</span>pid<span style="color:#f92672">).</span><span style="color:#a6e22e">get</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>9.创建Controller</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.controller<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ProductController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> ProductService productService<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//商品信息查询
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/product/{pid}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Product <span style="color:#a6e22e">findByPid</span><span style="color:#f92672">(</span><span style="color:#a6e22e">@PathVariable</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;pid&#34;</span><span style="color:#f92672">)</span> Long pid<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;接下来要进行{}号商品信息的查询&#34;</span><span style="color:#f92672">,</span> pid<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        Product product <span style="color:#f92672">=</span> productService<span style="color:#f92672">.</span><span style="color:#a6e22e">findByPid</span><span style="color:#f92672">(</span>pid<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;商品信息查询成功,内容为{}&#34;</span><span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>product<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> product<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>10.启动工程，等到数据库表创建完毕之后，加入测试数据</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#66d9ef">INSERT</span> <span style="color:#66d9ef">INTO</span> t_shop_product VALUE(<span style="color:#66d9ef">NULL</span>,<span style="color:#e6db74">&#39;小米&#39;</span>,<span style="color:#e6db74">&#39;1000&#39;</span>,<span style="color:#e6db74">&#39;5000&#39;</span>); 
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">INSERT</span> <span style="color:#66d9ef">INTO</span> t_shop_product VALUE(<span style="color:#66d9ef">NULL</span>,<span style="color:#e6db74">&#39;华为&#39;</span>,<span style="color:#e6db74">&#39;2000&#39;</span>,<span style="color:#e6db74">&#39;5000&#39;</span>); 
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">INSERT</span> <span style="color:#66d9ef">INTO</span> t_shop_product VALUE(<span style="color:#66d9ef">NULL</span>,<span style="color:#e6db74">&#39;苹果&#39;</span>,<span style="color:#e6db74">&#39;3000&#39;</span>,<span style="color:#e6db74">&#39;5000&#39;</span>); 
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">INSERT</span> <span style="color:#66d9ef">INTO</span> t_shop_product VALUE(<span style="color:#66d9ef">NULL</span>,<span style="color:#e6db74">&#39;OPPO&#39;</span>,<span style="color:#e6db74">&#39;4000&#39;</span>,<span style="color:#e6db74">&#39;5000&#39;</span>);
</span></span></code></pre></div><p>11.通过浏览器访问服务</p>
<p><strong><img src="%E5%9B%BE%E7%89%87/image-20201028160015063.png" alt="image-20201028160015063"></strong></p>
<h2 id="27-创建订单微服务">2.7 创建订单微服务</h2>
<p>1.创建shop-order-api项目，然后在pom.xml文件中添加下面内容</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#75715e">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;project</span> <span style="color:#a6e22e">xmlns=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xmlns:xsi=</span><span style="color:#e6db74">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xsi:schemaLocation=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;parent&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;artifactId&gt;</span>shop-parent<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;groupId&gt;</span>cn.czh0123<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;version&gt;</span>1.0.0<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/parent&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;modelVersion&gt;</span>4.0.0<span style="color:#f92672">&lt;/modelVersion&gt;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;artifactId&gt;</span>shop-order-api<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">&lt;!--依赖--&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;dependencies&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>org.springframework.boot<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>spring-boot-starter-data-jpa<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>org.projectlombok<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>lombok<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/dependencies&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/project&gt;</span>
</span></span></code></pre></div><p>2 创建实体类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//订单
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">@Entity</span><span style="color:#f92672">(</span>name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;t_shop_order&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Data</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Order</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Id</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@GeneratedValue</span><span style="color:#f92672">(</span>strategy <span style="color:#f92672">=</span> GenerationType<span style="color:#f92672">.</span><span style="color:#a6e22e">IDENTITY</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Long oid<span style="color:#f92672">;</span><span style="color:#75715e">//订单id
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//用户
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> Long uid<span style="color:#f92672">;</span><span style="color:#75715e">//用户id
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> String username<span style="color:#f92672">;</span><span style="color:#75715e">//用户名
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#75715e">//商品
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> Long pid<span style="color:#f92672">;</span><span style="color:#75715e">//商品id
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> String pname<span style="color:#f92672">;</span><span style="color:#75715e">//商品名称
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> Double pprice<span style="color:#f92672">;</span><span style="color:#75715e">//商品单价
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#75715e">//数量
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> Integer number<span style="color:#f92672">;</span><span style="color:#75715e">//购买数量
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>3.创建shop-order-server项目，然后在pom.xml文件中添加下面内容</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#75715e">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;project</span> <span style="color:#a6e22e">xmlns=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xmlns:xsi=</span><span style="color:#e6db74">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xsi:schemaLocation=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;parent&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;artifactId&gt;</span>shop-parent<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;groupId&gt;</span>cn.czh0123<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;version&gt;</span>1.0.0<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/parent&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;modelVersion&gt;</span>4.0.0<span style="color:#f92672">&lt;/modelVersion&gt;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;artifactId&gt;</span>shop-order-server<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;dependencies&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>org.springframework.boot<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>spring-boot-starter-web<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>mysql<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>mysql-connector-java<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>com.alibaba<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>fastjson<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;version&gt;</span>1.2.56<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>cn.czh0123<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>shop-order-api<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;version&gt;</span>1.0.0<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/dependencies&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/project&gt;</span>
</span></span></code></pre></div><p>4.编写启动类OrderServer.java</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@SpringBootApplication</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OrderServer</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        SpringApplication<span style="color:#f92672">.</span><span style="color:#a6e22e">run</span><span style="color:#f92672">(</span>OrderServer<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">,</span>args<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>5.编写配置文件application.yml</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">server</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">port</span>: <span style="color:#ae81ff">8091</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">application</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">order-service</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">datasource</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">driver-class-name</span>: <span style="color:#ae81ff">com.mysql.jdbc.Driver</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">url</span>: <span style="color:#ae81ff">jdbc:mysql:///shop-order?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">username</span>: <span style="color:#ae81ff">root</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">password</span>: <span style="color:#ae81ff">admin</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">jpa</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">properties</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">hibernate</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">hbm2ddl</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">auto</span>: <span style="color:#ae81ff">update</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">dialect</span>: <span style="color:#ae81ff">org.hibernate.dialect.MySQL5InnoDBDialect</span>
</span></span></code></pre></div><p>6.在数据库中创建shop-order的数据库</p>
<p>7.创建OrderDao</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.dao<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">OrderDao</span> <span style="color:#66d9ef">extends</span> JpaRepository<span style="color:#f92672">&lt;</span>Order<span style="color:#f92672">,</span> Long<span style="color:#f92672">&gt;</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>8.创建OrderService接口和实现类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.service.impl<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Service</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OrderServiceImpl</span> <span style="color:#66d9ef">implements</span> OrderService <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> OrderDao orderDao<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Order <span style="color:#a6e22e">createOrder</span><span style="color:#f92672">(</span>Long productId<span style="color:#f92672">,</span>Long userId<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息&#34;</span><span style="color:#f92672">,</span> productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//远程调用商品微服务,查询商品信息
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Product product <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;查询到{}号商品的信息,内容是:{}&#34;</span><span style="color:#f92672">,</span> productId<span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>product<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建订单并保存
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Order order <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Order<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setUid</span><span style="color:#f92672">(</span>userId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setUsername</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;叩丁狼教育&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPid</span><span style="color:#f92672">(</span>productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPname</span><span style="color:#f92672">(</span>product<span style="color:#f92672">.</span><span style="color:#a6e22e">getPname</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPprice</span><span style="color:#f92672">(</span>product<span style="color:#f92672">.</span><span style="color:#a6e22e">getPprice</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setNumber</span><span style="color:#f92672">(</span>1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        orderDao<span style="color:#f92672">.</span><span style="color:#a6e22e">save</span><span style="color:#f92672">(</span>order<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;创建订单成功,订单信息为{}&#34;</span><span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>order<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> order<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>9.创建Controller</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.controller<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OrderController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> OrderService orderService<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/save&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Order <span style="color:#a6e22e">order</span><span style="color:#f92672">(</span>Long pid<span style="color:#f92672">,</span>Long uid<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> orderService<span style="color:#f92672">.</span><span style="color:#a6e22e">createOrder</span><span style="color:#f92672">(</span>pid<span style="color:#f92672">,</span>uid<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><h2 id="28-服务间如何进行远程调用">2.8 服务间如何进行远程调用</h2>
<p>商品微服务已经提供了数据接口了，订单微服务应该如何去调用呢?</p>
<p><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111454614.png" alt="image-20201028172759047"></p>
<p>其实就是如何通过Java代码去调用一个http的接口地址，我们可以使用RestTemplate来进行调用.</p>
<p>1.在启动类上添加RestTemplate的bean配置</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@SpringBootApplication</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OrderServer</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        SpringApplication<span style="color:#f92672">.</span><span style="color:#a6e22e">run</span><span style="color:#f92672">(</span>OrderServer<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">,</span>args<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Bean</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> RestTemplate <span style="color:#a6e22e">restTemplate</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> RestTemplate<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>2.在OrderServiceImpl中注入RestTemplate并实现远程调用</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@Service</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OrderServiceImpl</span> <span style="color:#66d9ef">implements</span> OrderService <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> OrderDao orderDao<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> RestTemplate restTemplate<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Order <span style="color:#a6e22e">createOrder</span><span style="color:#f92672">(</span>Long productId<span style="color:#f92672">,</span>Long userId<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息&#34;</span><span style="color:#f92672">,</span> productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//远程调用商品微服务,查询商品信息
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Product product <span style="color:#f92672">=</span> restTemplate<span style="color:#f92672">.</span><span style="color:#a6e22e">getForObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">&#34;http://localhost:8081/product/&#34;</span><span style="color:#f92672">+</span>productId<span style="color:#f92672">,</span>Product<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;查询到{}号商品的信息,内容是:{}&#34;</span><span style="color:#f92672">,</span> productId<span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>product<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建订单并保存
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Order order <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Order<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setUid</span><span style="color:#f92672">(</span>userId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setUsername</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;叩丁狼教育&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPid</span><span style="color:#f92672">(</span>productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPname</span><span style="color:#f92672">(</span>product<span style="color:#f92672">.</span><span style="color:#a6e22e">getPname</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPprice</span><span style="color:#f92672">(</span>product<span style="color:#f92672">.</span><span style="color:#a6e22e">getPprice</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setNumber</span><span style="color:#f92672">(</span>1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        orderDao<span style="color:#f92672">.</span><span style="color:#a6e22e">save</span><span style="color:#f92672">(</span>order<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;创建订单成功,订单信息为{}&#34;</span><span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>order<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> order<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>虽然我们已经可以实现微服务之间的调用。但是我们把服务提供者的网络地址（ip，端口）等硬编码到了代码中，这种做法存在许多问题：</p>
<ul>
<li>
<p>一旦服务提供者地址变化，就需要手工修改代码</p>
</li>
<li>
<p>一旦是多个服务提供者，无法实现负载均衡功能</p>
</li>
<li>
<p>一旦服务变得越来越多，人工维护调用关系困难</p>
</li>
</ul>
<p>那么应该怎么解决呢， 这时候就需要通过注册中心动态的实现<strong>服务治理</strong>。</p>
<h1 id="第三章-服务治理--nacos-discovery">第三章 服务治理  Nacos Discovery</h1>
<h2 id="31-什么是服务治理">3.1 什么是服务治理</h2>
<p>服务治理是微服务架构中最核心最基本的模块。用于实现各个微服务的<strong>自动化注册与发现</strong>。</p>
<p>**服务注册：**在服务治理框架中，都会构建一个注册中心，每个服务单元向注册中心登记自己提供服</p>
<p>务的详细信息。并在注册中心形成一张服务的清单，服务注册中心需要以心跳的方式去监测清单中</p>
<p>的服务是否可用，如果不可用，需要在服务清单中剔除不可用的服务。</p>
<p>**服务发现：**服务调用方向服务注册中心咨询服务，并获取所有服务的实例清单，实现对具体服务实</p>
<p>例的访问。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111454780.png" alt="image-20201029084800199"></strong></p>
<p>通过上面的调用图会发现，除了微服务，还有一个组件是<strong>服务注册中心</strong>，它是微服务架构非常重要</p>
<p>的一个组件，在微服务架构里主要起到了协调者的一个作用。注册中心一般包含如下几个功能：</p>
<ol>
<li>服务发现：</li>
</ol>
<p>服务注册：保存服务提供者和服务调用者的信息</p>
<p>服务订阅：服务调用者订阅服务提供者的信息，注册中心向订阅者推送提供者的信息</p>
<ol start="2">
<li>服务健康检测</li>
</ol>
<p>检测服务提供者的健康情况，如果发现异常，执行服务剔除</p>
<h2 id="32-常见注册中心">3.2 常见注册中心</h2>
<ul>
<li>
<p><strong>Zookeeper</strong></p>
<p>Zookeeper是一个分布式服务框架，是Apache Hadoop 的一个子项目，它主要是用来解决分布式应用中经常遇到的一些数据管理问题，如：统一命名服务、状态同步服务、集群管理、分布式应用</p>
</li>
</ul>
<p>配置项的管理等。</p>
<ul>
<li>
<p><strong>Eureka</strong></p>
<p>Eureka是Springcloud Netflflix中的重要组件，主要作用就是做服务注册和发现。但是现在已经闭源</p>
</li>
<li>
<p><strong>Consul</strong></p>
<p>Consul是基于GO语言开发的开源工具，主要面向分布式，服务化的系统提供服务注册、服务发现</p>
</li>
</ul>
<p>和配置管理的功能。Consul的功能都很实用，其中包括：服务注册/发现、健康检查、Key/Value</p>
<p>存储、多数据中心和分布式一致性保证等特性。Consul本身只是一个二进制的可执行文件，所以</p>
<p>安装和部署都非常简单，只需要从官网下载后，在执行对应的启动脚本即可。</p>
<ul>
<li>
<p><strong>Nacos</strong></p>
<p>Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它是 SpringCloud Alibaba 组件之一，负责服务注册发现和服务配置。</p>
</li>
</ul>
<h2 id="33-nacos-简介">3.3 Nacos 简介</h2>
<p>Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集，帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。</p>
<p>从上面的介绍就可以看出，Nacos的作用就是一个注册中心，用来管理注册上来的各个微服务。</p>
<p><strong>核心功能点</strong>:</p>
<ul>
<li>
<p><strong>服务注册</strong>:  Nacos Client会通过发送REST请求想Nacos Server注册自己的服务，提供自身的元数据，比如IP地址，端口等信息。Nacos Server接收到注册请求后，就会把这些元数据存储到一个双层的内存Map中。</p>
</li>
<li>
<p><strong>服务心跳</strong>:  在服务注册后，Nacos Client会维护一个定时心跳来维持统治Nacos Server,说明服务一致处于可用状态，防止被剔除，默认5s发送一次心跳</p>
</li>
<li>
<p><strong>服务同步</strong>:  Nacos Server集群之间会相互同步服务实例，用来保证服务信息的一致性。</p>
</li>
<li>
<p><strong>服务发现</strong>： 服务消费者(Nacos Client)在调用服务提供的服务时，会发送一个REST请求给Nacos Server,获取上面注册的服务清单，并且缓存在Nacos Client本地,同时会在Nacos Client本地开启一个定时任务拉取服务最新的注册表信息更新到本地缓存。</p>
</li>
<li>
<p><strong>服务健康检查</strong>:  Nacos Server 会开启一个定时任务来检查注册服务实例的健康情况，对于超过15s没有收到客户端心跳的实例会将他的healthy属性设置为false(客户端服务发现时不会发现)，如果某个实例超过30s没有收到心跳，直接剔除该实例(被剔除的实例如果恢复发送心跳则会重新注册)</p>
</li>
</ul>
<h2 id="34-nacos实战入门">3.4 Nacos实战入门</h2>
<p>接下来，我们就在现有的环境中加入nacos，并将我们的两个微服务注册上去。</p>
<h3 id="341-搭建nacos环境">3.4.1 搭建Nacos环境</h3>
<ol>
<li>
<p>安装Nacos</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>下载地址: https://github.com/alibaba/nacos/releases 
</span></span><span style="display:flex;"><span>下载zip格式的安装包，然后进行解压缩操作,上课使用的Nacos Server版本是1.3.2
</span></span></code></pre></div></li>
<li>
<p>启动Nacos</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e">#切换目录 </span>
</span></span><span style="display:flex;"><span>cd nacos/bin 
</span></span><span style="display:flex;"><span><span style="color:#75715e">#命令启动 </span>
</span></span><span style="display:flex;"><span>startup.cmd -m standalone
</span></span></code></pre></div></li>
<li>
<p>访问Nacos</p>
<p>打开浏览器输入http://localhost:8848/nacos，即可访问服务， 默认密码是nacos/nacos</p>
</li>
</ol>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111454178.png" alt="image-20201029092937927"></strong></p>
<h3 id="342-将商品服务注册到nacos">3.4.2 将商品服务注册到Nacos</h3>
<p>接下来开始修改 shop-product-server 模块的代码， 将其注册到nacos服务上</p>
<ol>
<li>在pom.xml中添加Nacos的依赖</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#75715e">&lt;!--nacos客户端--&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;groupId&gt;</span>com.alibaba.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-starter-alibaba-nacos-discovery<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span></code></pre></div><ol start="2">
<li>
<p>在主类上添加**@EnableDiscoveryClient**注解</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@SpringBootApplication</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@EnableDiscoveryClient</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ProductServer</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        SpringApplication<span style="color:#f92672">.</span><span style="color:#a6e22e">run</span><span style="color:#f92672">(</span>ProductServer<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">,</span>args<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>在application.yml中添加Nacos服务的地址</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>: 
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">nacos</span>: 
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">discovery</span>: 
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">server-addr</span>: <span style="color:#ae81ff">localhost:8848</span>
</span></span></code></pre></div></li>
<li>
<p>启动服务， 观察Nacos的控制面板中是否有注册上来的商品微服务</p>
</li>
</ol>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111454917.png" alt="image-20201029094004073"></strong></p>
<h3 id="343-将订单服务注册到nacos">3.4.3 将订单服务注册到Nacos</h3>
<p>接下来开始修改 shop-order-server 模块的代码， 将其注册到nacos服务上</p>
<ol>
<li>在pom.xml中添加Nacos的依赖</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#75715e">&lt;!--nacos客户端--&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;groupId&gt;</span>com.alibaba.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-starter-alibaba-nacos-discovery<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span></code></pre></div><ol start="2">
<li>
<p>在主类上添加**@EnableDiscoveryClient**注解</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@SpringBootApplication</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@EnableDiscoveryClient</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OrderServer</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        SpringApplication<span style="color:#f92672">.</span><span style="color:#a6e22e">run</span><span style="color:#f92672">(</span>OrderServer<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">,</span>args<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>在application.yml中添加Nacos服务的地址</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>: 
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">nacos</span>: 
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">discovery</span>: 
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">server-addr</span>: <span style="color:#ae81ff">localhost:8848</span>
</span></span></code></pre></div><ol start="4">
<li>启动服务， 观察Nacos的控制面板中是否有注册上来的订单微服务</li>
</ol>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111454148.png" alt="image-20201029094943183"></strong></p>
<ol start="5">
<li>修改OrderServiceImpl， 实现微服务调用</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@Service</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OrderServiceImpl</span> <span style="color:#66d9ef">implements</span> OrderService <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> OrderDao orderDao<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> DiscoveryClient discoveryClient<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> RestTemplate restTemplate<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Order <span style="color:#a6e22e">createOrder</span><span style="color:#f92672">(</span>Long productId<span style="color:#f92672">,</span>Long userId<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息&#34;</span><span style="color:#f92672">,</span> productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//从nacos中获取服务地址
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ServiceInstance instance <span style="color:#f92672">=</span> discoveryClient<span style="color:#f92672">.</span>
</span></span><span style="display:flex;"><span>                <span style="color:#a6e22e">getInstances</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;product-service&#34;</span><span style="color:#f92672">).</span><span style="color:#a6e22e">get</span><span style="color:#f92672">(</span>0<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        String url <span style="color:#f92672">=</span> instance<span style="color:#f92672">.</span><span style="color:#a6e22e">getHost</span><span style="color:#f92672">()+</span><span style="color:#e6db74">&#34;:&#34;</span><span style="color:#f92672">+</span>instance<span style="color:#f92672">.</span><span style="color:#a6e22e">getPort</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//远程调用商品微服务,查询商品信息
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Product product <span style="color:#f92672">=</span> restTemplate<span style="color:#f92672">.</span><span style="color:#a6e22e">getForObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">&#34;http://&#34;</span><span style="color:#f92672">+</span>url<span style="color:#f92672">+</span><span style="color:#e6db74">&#34;/product/&#34;</span><span style="color:#f92672">+</span>productId<span style="color:#f92672">,</span>Product<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;查询到{}号商品的信息,内容是:{}&#34;</span><span style="color:#f92672">,</span> productId<span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>product<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建订单并保存
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Order order <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Order<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setUid</span><span style="color:#f92672">(</span>userId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setUsername</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;叩丁狼教育&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPid</span><span style="color:#f92672">(</span>productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPname</span><span style="color:#f92672">(</span>product<span style="color:#f92672">.</span><span style="color:#a6e22e">getPname</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPprice</span><span style="color:#f92672">(</span>product<span style="color:#f92672">.</span><span style="color:#a6e22e">getPprice</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setNumber</span><span style="color:#f92672">(</span>1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        orderDao<span style="color:#f92672">.</span><span style="color:#a6e22e">save</span><span style="color:#f92672">(</span>order<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;创建订单成功,订单信息为{}&#34;</span><span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>order<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> order<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><h1 id="第四章-远程调用负载均衡-ribbon">第四章 远程调用负载均衡 Ribbon</h1>
<h2 id="41-什么是负载均衡">4.1 什么是负载均衡</h2>
<p>通俗的讲， 负载均衡就是将负载（工作任务，访问请求）进行分摊到多个操作单元（服务器,组件）上</p>
<p>进行执行。</p>
<p>根据负载均衡发生位置的不同,一般分为<strong>服务端负载均衡</strong>和<strong>客户端负载均衡</strong>。</p>
<p>服务端负载均衡指的是发生在服务提供者一方,比如常见的Nginx负载均衡</p>
<p>而客户端负载均衡指的是发生在服务请求的一方，也就是在发送请求之前已经选好了由哪个实例处理请</p>
<p>求</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111454502.png" alt="image-20201029102235075"></strong></p>
<p>我们在微服务调用关系中一般会选择客户端负载均衡，也就是在服务调用的一方来决定服务由哪个提供</p>
<p>者执行。</p>
<h2 id="42-自定义负载均衡">4.2 自定义负载均衡</h2>
<ol>
<li>
<p>通过idea再启动一个 shop-product 微服务，设置其端口为8082</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111454377.png" alt="image-20201029102538473"></strong></p>
</li>
<li>
<p>通过nacos查看微服务的启动情况</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111454606.png" alt="image-20201029102905790"></strong></p>
</li>
<li>
<p>修改 OrderServiceImpl 的代码，实现负载均衡</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@Service</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OrderServiceImpl</span> <span style="color:#66d9ef">implements</span> OrderService <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> OrderDao orderDao<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> DiscoveryClient discoveryClient<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> RestTemplate restTemplate<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Order <span style="color:#a6e22e">createOrder</span><span style="color:#f92672">(</span>Long productId<span style="color:#f92672">,</span>Long userId<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息&#34;</span><span style="color:#f92672">,</span> productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//从nacos中获取服务地址
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#75715e">//自定义规则实现随机挑选服务
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        List<span style="color:#f92672">&lt;</span>ServiceInstance<span style="color:#f92672">&gt;</span> instances <span style="color:#f92672">=</span> discoveryClient<span style="color:#f92672">.</span>
</span></span><span style="display:flex;"><span>                <span style="color:#a6e22e">getInstances</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;product-service&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">int</span> index <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Random<span style="color:#f92672">().</span><span style="color:#a6e22e">nextInt</span><span style="color:#f92672">(</span>instances<span style="color:#f92672">.</span><span style="color:#a6e22e">size</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        ServiceInstance instance <span style="color:#f92672">=</span> instances<span style="color:#f92672">.</span><span style="color:#a6e22e">get</span><span style="color:#f92672">(</span>index<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        String url <span style="color:#f92672">=</span> instance<span style="color:#f92672">.</span><span style="color:#a6e22e">getHost</span><span style="color:#f92672">()+</span><span style="color:#e6db74">&#34;:&#34;</span><span style="color:#f92672">+</span>instance<span style="color:#f92672">.</span><span style="color:#a6e22e">getPort</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;&gt;&gt;从nacos中获取到的微服务地址为:&#34;</span> <span style="color:#f92672">+</span> url<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//远程调用商品微服务,查询商品信息
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Product product <span style="color:#f92672">=</span> restTemplate<span style="color:#f92672">.</span><span style="color:#a6e22e">getForObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">&#34;http://&#34;</span><span style="color:#f92672">+</span>url<span style="color:#f92672">+</span><span style="color:#e6db74">&#34;/product/&#34;</span><span style="color:#f92672">+</span>productId<span style="color:#f92672">,</span>Product<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;查询到{}号商品的信息,内容是:{}&#34;</span><span style="color:#f92672">,</span> productId<span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>product<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建订单并保存
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Order order <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Order<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setUid</span><span style="color:#f92672">(</span>userId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setUsername</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;叩丁狼教育&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPid</span><span style="color:#f92672">(</span>productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPname</span><span style="color:#f92672">(</span>product<span style="color:#f92672">.</span><span style="color:#a6e22e">getPname</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPprice</span><span style="color:#f92672">(</span>product<span style="color:#f92672">.</span><span style="color:#a6e22e">getPprice</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setNumber</span><span style="color:#f92672">(</span>1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        orderDao<span style="color:#f92672">.</span><span style="color:#a6e22e">save</span><span style="color:#f92672">(</span>order<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;创建订单成功,订单信息为{}&#34;</span><span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>order<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> order<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><ol start="4">
<li>
<p>启动两个服务提供者和一个服务消费者，多访问几次消费者测试效果</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455232.png" alt="image-20201029103519605"></strong></p>
</li>
</ol>
<h2 id="43-基于ribbon实现负载均衡">4.3 基于Ribbon实现负载均衡</h2>
<p>Ribbon是Spring Cloud的一个组件， 它可以让我们使用一个注解就能轻松的搞定负载均衡</p>
<ol>
<li>
<p>在RestTemplate 的生成方法上添加@LoadBalanced注解</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@Bean</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@LoadBalanced</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> RestTemplate <span style="color:#a6e22e">restTemplate</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> RestTemplate<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>修改OrderServiceImpl服务调用的方法</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@Service</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OrderServiceImpl</span> <span style="color:#66d9ef">implements</span> OrderService <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> OrderDao orderDao<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> RestTemplate restTemplate<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Order <span style="color:#a6e22e">createOrder</span><span style="color:#f92672">(</span>Long productId<span style="color:#f92672">,</span>Long userId<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息&#34;</span><span style="color:#f92672">,</span> productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//远程调用商品微服务,查询商品信息
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Product product <span style="color:#f92672">=</span> restTemplate<span style="color:#f92672">.</span><span style="color:#a6e22e">getForObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">&#34;http://product-service/product/&#34;</span><span style="color:#f92672">+</span>productId<span style="color:#f92672">,</span>Product<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;查询到{}号商品的信息,内容是:{}&#34;</span><span style="color:#f92672">,</span> productId<span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>product<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建订单并保存
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Order order <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Order<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setUid</span><span style="color:#f92672">(</span>userId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setUsername</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;叩丁狼教育&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPid</span><span style="color:#f92672">(</span>productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPname</span><span style="color:#f92672">(</span>product<span style="color:#f92672">.</span><span style="color:#a6e22e">getPname</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPprice</span><span style="color:#f92672">(</span>product<span style="color:#f92672">.</span><span style="color:#a6e22e">getPprice</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setNumber</span><span style="color:#f92672">(</span>1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        orderDao<span style="color:#f92672">.</span><span style="color:#a6e22e">save</span><span style="color:#f92672">(</span>order<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;创建订单成功,订单信息为{}&#34;</span><span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>order<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> order<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>为了更直观看到请求是进行负载均衡了，我们修改一下ProductController代码</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ProductController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> ProductService productService<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Value</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;${server.port}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String port<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//商品信息查询
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/product/{pid}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Product <span style="color:#a6e22e">findByPid</span><span style="color:#f92672">(</span><span style="color:#a6e22e">@PathVariable</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;pid&#34;</span><span style="color:#f92672">)</span> Long pid<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;接下来要进行{}号商品信息的查询&#34;</span><span style="color:#f92672">,</span> pid<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        Product product <span style="color:#f92672">=</span> productService<span style="color:#f92672">.</span><span style="color:#a6e22e">findByPid</span><span style="color:#f92672">(</span>pid<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        product<span style="color:#f92672">.</span><span style="color:#a6e22e">setPname</span><span style="color:#f92672">(</span>product<span style="color:#f92672">.</span><span style="color:#a6e22e">getPname</span><span style="color:#f92672">()+</span><span style="color:#e6db74">&#34;,data from &#34;</span><span style="color:#f92672">+</span>port<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;商品信息查询成功,内容为{}&#34;</span><span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>product<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> product<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>调用订单保存的方法，查看日志.</p>
<p><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455143.png" alt="image-20201029105040492"></p>
</li>
</ol>
<p>默认情况下,采取的是ZoneAvoidanceRule的策略,复合判断server所在区域的性能和server的可用性选择server</p>
<p><strong>Ribbon支持的负载均衡策略</strong></p>
<p>Ribbon内置了多种负载均衡策略,内部负载均衡的顶级接口为</p>
<p>com.netflix.loadbalancer.IRule , 具体的负载策略如下图所示:</p>
<table>
<thead>
<tr>
<th>策略名</th>
<th>策略描述</th>
<th>实现说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>BestAvailableRule</td>
<td>选择一个最小的并发请求的server</td>
<td>逐个考察Server，如果Server被tripped了，则忽略，在选择其中ActiveRequestsCount最小的server</td>
</tr>
<tr>
<td>AvailabilityFilteringRule</td>
<td>先过滤掉故障实例，再选择并发较小的实例；</td>
<td>使用一个AvailabilityPredicate来包含过滤server的逻辑，其实就就是检查status里记录的各个server的运行状态</td>
</tr>
<tr>
<td>WeightedResponseTimeRule</td>
<td>根据相应时间分配一个weight，相应时间越长，weight越小，被选中的可能性越低。</td>
<td>一个后台线程定期的从status里面读取评价响应时间，为每个server计算一个weight。Weight的计算也比较简单responsetime 减去每个server自己平均的responsetime是server的权</td>
</tr>
<tr>
<td>RetryRule</td>
<td>对选定的负载均衡策略机上重试机制。</td>
<td>在一个配置时间段内当选择server不成功，则一直尝试使用subRule的方式选择一个可用的server</td>
</tr>
<tr>
<td>RoundRobinRule</td>
<td>轮询方式轮询选择server</td>
<td>轮询index，选择index对应位置的server</td>
</tr>
<tr>
<td>RandomRule</td>
<td>随机选择一个server</td>
<td>在index上随机，选择index对应位置的server</td>
</tr>
<tr>
<td>ZoneAvoidanceRule(默认)</td>
<td>复合判断server所在区域的性能和server的可用性选择server</td>
<td>使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server，前一个判断判定一个zone的运行性能是否可用，剔除不可用的zone（的所有server），AvailabilityPredicate用于过滤掉连接数过多的Server。</td>
</tr>
</tbody>
</table>
<p>我们可以通过修改配置来调整Ribbon的负载均衡策略，在order-server项目的application.yml中增加如下配置:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">product-service</span>: <span style="color:#75715e"># 调用的提供者的名称</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">ribbon</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">NFLoadBalancerRuleClassName</span>: <span style="color:#ae81ff">com.netflix.loadbalancer.RandomRule</span>
</span></span></code></pre></div><h1 id="第五章-远程调用openfeign">第五章 远程调用OpenFeign</h1>
<blockquote>
<p>==feign 动态代理 给接口生成一个实现类,在这个实现类中,用RestTemplate远程调用服务的方法==</p>
</blockquote>
<h2 id="51-什么是openfeign">5.1 什么是OpenFeign</h2>
<p>​	Feign是Spring Cloud提供的一个声明式的伪Http客户端， 它使得调用远程服务就像调用本地服务</p>
<p>一样简单， 只需要创建一个接口并添加一个注解即可。</p>
<p>​	Nacos很好的兼容了Feign， Feign默认集成了 Ribbon， 所以在Nacos下使用Fegin默认就实现了负</p>
<p>载均衡的效果。</p>
<h2 id="52-订单微服务集成feign">5.2 订单微服务集成Feign</h2>
<ol>
<li>
<p>在shop-order-server项目的pom文件加入Fegin的依赖</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#75715e">&lt;!--fegin组件--&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;groupId&gt;</span>org.springframework.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-starter-openfeign<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span></code></pre></div></li>
<li>
<p>在启动类OrderServer.java上添加Fegin的扫描注解,注意扫描路径(默认扫描当前包及其子包)</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@SpringBootApplication</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@EnableDiscoveryClient</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@EnableFeignClients</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OrderServer</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        SpringApplication<span style="color:#f92672">.</span><span style="color:#a6e22e">run</span><span style="color:#f92672">(</span>OrderServer<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">,</span>args<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><ol start="3">
<li>
<p>在shop-order-server项目中新增接口ProductFeignApi</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.feign<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//name的名称一定要和订单服务的服务名保持一致
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">@FeignClient</span><span style="color:#f92672">(</span>name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;product-service&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">ProductFeignApi</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/product/{pid}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Product <span style="color:#a6e22e">findByPid</span><span style="color:#f92672">(</span><span style="color:#a6e22e">@PathVariable</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;pid&#34;</span><span style="color:#f92672">)</span> Long pid<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>修改OrderServiceImpl.java的远程调用方法</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@Service</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OrderServiceImpl</span> <span style="color:#66d9ef">implements</span> OrderService <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> OrderDao orderDao<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> ProductFeignApi productFeignApi<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Order <span style="color:#a6e22e">createOrder</span><span style="color:#f92672">(</span>Long productId<span style="color:#f92672">,</span>Long userId<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息&#34;</span><span style="color:#f92672">,</span> productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//远程调用商品微服务,查询商品信息
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Product product <span style="color:#f92672">=</span> productFeignApi<span style="color:#f92672">.</span><span style="color:#a6e22e">findByPid</span><span style="color:#f92672">(</span>productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;查询到{}号商品的信息,内容是:{}&#34;</span><span style="color:#f92672">,</span> productId<span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>product<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建订单并保存
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Order order <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Order<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setUid</span><span style="color:#f92672">(</span>userId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setUsername</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;叩丁狼教育&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPid</span><span style="color:#f92672">(</span>productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPname</span><span style="color:#f92672">(</span>product<span style="color:#f92672">.</span><span style="color:#a6e22e">getPname</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setPprice</span><span style="color:#f92672">(</span>product<span style="color:#f92672">.</span><span style="color:#a6e22e">getPprice</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        order<span style="color:#f92672">.</span><span style="color:#a6e22e">setNumber</span><span style="color:#f92672">(</span>1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        orderDao<span style="color:#f92672">.</span><span style="color:#a6e22e">save</span><span style="color:#f92672">(</span>order<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;创建订单成功,订单信息为{}&#34;</span><span style="color:#f92672">,</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>order<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> order<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>重启订单服务，并验证.</p>
</li>
</ol>
<h1 id="第六章-服务熔断降级-sentinel">第六章 服务熔断降级 Sentinel</h1>
<h2 id="61-高并发带来的问题">6.1 高并发带来的问题</h2>
<p>​	在微服务架构中，我们将业务拆分成一个个的服务，服务与服务之间可以相互调用，但是由于网络原因或者自身的原因，服务并不能保证服务的100%可用，如果单个服务出现问题，调用这个服务就会出现网络延迟，此时若有大量的网络涌入，会形成任务堆积，最终导致服务瘫痪。</p>
<p><strong>接下来，我们来模拟一个高并发的场景</strong></p>
<ol>
<li>
<p>在订单服务中新建SentinelController.java</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SentinelController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/sentinel1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">sentinel1</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//模拟一次网络延时
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            TimeUnit<span style="color:#f92672">.</span><span style="color:#a6e22e">SECONDS</span><span style="color:#f92672">.</span><span style="color:#a6e22e">sleep</span><span style="color:#f92672">(</span>1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span> <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>InterruptedException e<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            e<span style="color:#f92672">.</span><span style="color:#a6e22e">printStackTrace</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;sentinel1&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/sentinel2&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">sentinel2</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;测试高并发下的问题&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>修改配置文件中tomcat的并发数</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">server</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">port</span>: <span style="color:#ae81ff">8091</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">tomcat</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">threads</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">max</span>: <span style="color:#ae81ff">10</span> <span style="color:#75715e">#tomcat的最大并发值修改为10</span>
</span></span></code></pre></div></li>
<li>
<p>接下来使用压测工具,对请求进行压力测试</p>
<p>下载地址https://jmeter.apache.org/</p>
<ul>
<li>
<p>第一步：修改配置，并启动软件</p>
<p>进入bin目录,修改jmeter.properties文件中的语言支持为language=zh_CN，然后点击jmeter.bat</p>
<p>启动软件。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455986.png" alt="image-20201029115836172"></strong></p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455304.png" alt="image-20201029115935101"></strong></p>
</li>
<li>
<p>第二步：添加线程组</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455830.png" alt="image-20201029120234401"></strong></p>
</li>
<li>
<p>第三步：配置线程并发数</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455869.png" alt="image-20201029124003847"></strong></p>
</li>
<li>
<p>第四步：添加Http请求</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455654.png" alt="image-20201029122851926"></strong></p>
</li>
<li>
<p>第五步：配置取样，并启动测试</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455504.png" alt="image-20201029123042028"></strong></p>
</li>
</ul>
<p>第六步：访问 http://localhost:8091/sentinel2 观察结果</p>
<p><strong>结论</strong>:此时会发现, 由于sentinel1方法囤积了大量请求, 导致sentinel2方法的访问出现了问题，这就是服务雪</p>
<p>崩的雏形。</p>
<h2 id="62-服务器雪崩效应">6.2 服务器雪崩效应</h2>
<p>​	在分布式系统中,由于网络原因或自身的原因,服务一般无法保证 100% 可用。如果一个服务出现了问题，调用这个服务就会出现线程阻塞的情况，此时若有大量的请求涌入，就会出现多条线程阻塞等待，进而导致服务瘫痪。</p>
<p>​	由于服务与服务之间的依赖性，故障会传播，会对整个微服务系统造成灾难性的严重后果，这就是服务故障的 “<strong>雪崩效应</strong>” 。</p>
<ul>
<li>
<p>情景1: 微服务之间相互调用,关系复杂,正常情况如下图所示:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455359.png" alt="image-20201029125354604"></strong></p>
</li>
<li>
<p>情景2：某个时刻，服务A挂了，服务B和服务C依然在调用服务A</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456111.png" alt="image-20201029135409624"></strong></p>
</li>
<li>
<p>情景3:由于服务A挂了,导致服务C和服务B无法得到服务A的响应,这时候服务C和服务B由于大量线程积压,最终导致服务C和服务B挂掉.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456153.png" alt="image-20201029140115122"></strong></p>
</li>
<li>
<p>情景4: 相同道理,由于服务之间有关联，所以会导致整个调用链上的所有服务都挂掉.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456016.png" alt="image-20201029140259527"></strong></p>
</li>
</ul>
<p>​	服务器的雪崩效应其实就是由于某个微小的服务挂了,导致整一大片的服务都不可用.类似生活中的雪崩效应,由于落下的最后一片雪花引发了雪崩的情况.</p>
<p>​	雪崩发生的原因多种多样，有不合理的容量设计，或者是高并发下某一个方法响应变慢，亦或是某台机器的资源耗尽。我们无法完全杜绝雪崩源头的发生，只有做好足够的容错，保证在一个服务发生问题，不会影响到其它服务的正常运行。</p>
</li>
</ol>
<h2 id="62-常见容错方案">6.2 常见容错方案</h2>
<p>​	要防止雪崩的扩散，我们就要做好服务的容错，容错说白了就是保护自己不被猪队友拖垮的一些措施, 下面介绍常见的服务容错思路和组件。</p>
<p><strong>常见的容错思路</strong></p>
<p>常见的容错思路有==隔离、超时、限流、熔断、降级==这几种，下面分别介绍一下。</p>
<ul>
<li>
<p><strong>隔离机制</strong>: 比如服务A内总共有100个线程, 现在服务A可能会调用服务B,服务C,服务D.我们在服务A进行远程调用的时候,给不同的服务分配固定的线程,不会把所有线程都分配给某个微服务. 比如调用服务B分配30个线程,调用服务C分配30个线程，调用服务D分配40个线程. 这样进行资源的隔离，保证即使下游某个服务挂了，也不至于把服务A的线程消耗完。比如服务B挂了，这时候最多只会占用服务A的30个线程,服务A还有70个线程可以调用服务C和服务D.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456722.png" alt="image-20201029142100450"></strong></p>
</li>
<li>
<p><strong>超时机制</strong>: 在上游服务调用下游服务的时候，设置一个最大响应时间，如果超过这个时间，下游未作出反应，就断开请求，释放掉线程。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456667.png" alt="image-20201029143237828"></strong></p>
</li>
<li>
<p><strong>限流机制</strong>: 限流就是限制系统的输入和输出流量已达到保护系统的目的。为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456296.png" alt="image-20201029143206491"></strong></p>
</li>
<li>
<p><strong>熔断机制</strong>: 在互联网系统中，当下游服务因访问压力过大而响应变慢或失败，上游服务为了保护系统整体的可用性，可以暂时切断对下游服务的调用。这种牺牲局部，保全整体的措施就叫做熔断。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456996.png" alt="image-20201029143128555"></strong></p>
<p>服务熔断一般有三种状态：</p>
<ul>
<li>熔断关闭状态（Closed）</li>
</ul>
<p>服务没有故障时，熔断器所处的状态，对调用方的调用不做任何限制</p>
<ul>
<li>熔断开启状态（Open）</li>
</ul>
<p>后续对该服务接口的调用不再经过网络，直接执行本地的fallback方法</p>
<ul>
<li>半熔断状态（Half-Open）</li>
</ul>
<p>尝试恢复服务调用，允许有限的流量调用该服务，并监控调用成功率。如果成功率达到预期，则说明服务已恢复，进入熔断关闭状态；如果成功率仍旧很低，则重新进入熔断关闭状态。</p>
</li>
<li>
<p><strong>降级机制</strong>: 降级其实就是为服务提供一个兜底方案，一旦服务无法正常调用，就使用兜底方案。</p>
</li>
</ul>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456399.png" alt="image-20201029143456888"></strong></p>
<h2 id="63-常见的容错组件">6.3 常见的容错组件</h2>
<ul>
<li><strong>Hystrix</strong></li>
</ul>
<p>Hystrix是由Netflflix开源的一个延迟和容错库，用于隔离访问远程系统、服务或者第三方库，防止</p>
<p>级联失败，从而提升系统的可用性与容错性。</p>
<ul>
<li><strong>Resilience4J</strong></li>
</ul>
<p>Resilicence4J一款非常轻量、简单，并且文档非常清晰、丰富的熔断工具，这也是Hystrix官方推</p>
<p>荐的替代产品。不仅如此，Resilicence4j还原生支持Spring Boot 1.x/2.x，而且监控也支持和</p>
<p>prometheus等多款主流产品进行整合。</p>
<ul>
<li><strong>Sentinel</strong></li>
</ul>
<p>Sentinel 是阿里巴巴开源的一款断路器实现，本身在阿里内部已经被大规模采用，非常稳定。</p>
<h2 id="64-sentinel入门">6.4 Sentinel入门</h2>
<h3 id="641-什么是sentinel">6.4.1 什么是Sentinel</h3>
<p>Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于<strong>服务容错</strong>的综合性解决方案。它以流量为切入点, 从<strong>流量控制、熔断降级、系统负载保护</strong>等多个维度来保护服务的稳定性</p>
<p>Sentinel 具有以下特征:</p>
<ul>
<li>
<p><strong>丰富的应用场景</strong>：Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景, 例如秒杀（即突发流量控制在系统容量可以承受的范围）、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。</p>
</li>
<li>
<p><strong>完备的实时监控</strong>：Sentinel 提供了实时的监控功能。通过控制台可以看到接入应用的单台机器秒级数据, 甚至 500 台以下规模的集群的汇总运行情况。</p>
</li>
<li>
<p><strong>广泛的开源生态</strong>：Sentinel 提供开箱即用的与其它开源框架/库的整合模块, 例如与 SpringCloud、Dubbo、gRPC 的整合。只需要引入相应的依赖并进行简单的配置即可快速地接入Sentinel。</p>
</li>
</ul>
<p><strong>Sentinel分为两个部分</strong>:</p>
<ul>
<li>
<p>核心库（Java 客户端）不依赖任何框架/库,能够运行于所有 Java 运行时环境，同时对 Dubbo /Spring Cloud 等框架也有较好的支持。</p>
</li>
<li>
<p>控制台（Dashboard）基于 Spring Boot 开发，打包后可以直接运行，不需要额外的 Tomcat 等应用容器。</p>
</li>
</ul>
<h3 id="642-订单微服务集成sentinel">6.4.2 订单微服务集成Sentinel</h3>
<p>为微服务集成Sentinel非常简单, 只需要加入Sentinel的依赖即可</p>
<p>在shop-order-server项目的pom文件中添加如下依赖</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#75715e">&lt;!--sentinel组件--&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;groupId&gt;</span>com.alibaba.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-starter-alibaba-sentinel<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span></code></pre></div><h3 id="643-安装sentinel控制台">6.4.3 安装Sentinel控制台</h3>
<p>Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能。</p>
<ol>
<li>
<p>下载jar包 <a href="https://github.com/alibaba/Sentinel/releases">https://github.com/alibaba/Sentinel/releases</a></p>
</li>
<li>
<p>启动控制台</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># 直接使用jar命令启动项目(控制台本身是一个SpringBoot项目) </span>
</span></span><span style="display:flex;"><span>java -Dserver.port<span style="color:#f92672">=</span><span style="color:#ae81ff">8080</span> -Dcsp.sentinel.dashboard.server<span style="color:#f92672">=</span>localhost:8080 -Dproject.name<span style="color:#f92672">=</span>sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
</span></span></code></pre></div><ol start="3">
<li>
<p>修改shop-order-server项目中的配置文件application.yml,新增如下配置:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">sentinel</span>: 
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">transport</span>: 
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">port</span>: <span style="color:#ae81ff">9999</span> <span style="color:#75715e">#跟控制台交流的端口,随意指定一个未使用的端口即可 </span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">dashboard</span>: <span style="color:#ae81ff">localhost:8080</span> <span style="color:#75715e"># 指定控制台服务的地址</span>
</span></span></code></pre></div></li>
<li>
<p>通过浏览器访问localhost:8080 进入控制台 ( 默认用户名密码是 sentinel/sentinel )</p>
<p>注意: 默认是没显示order-service的，需要访问几次接口，然后再刷新sentinel管控台才可以看到.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456901.png" alt="image-20201029151420936"></strong></p>
</li>
</ol>
<h3 id="644-实现一个接口的限流">6.4.4 实现一个接口的限流</h3>
<p>第一步: 簇点链路&mdash;&gt;流控</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456099.png" alt="image-20201029151937258"></strong></p>
<p>第二步: 在单机阈值填写一个数值，表示每秒上限的请求数</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456459.png" alt="image-20201029152031334"></strong></p>
<p>第三步:通过控制台快速频繁访问, 观察效果</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456248.png" alt="image-20201029152401508"></strong></p>
<h3 id="645-sentinel容错的维度">6.4.5 Sentinel容错的维度</h3>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456167.png" alt="image-20201029153848900"></strong></p>
<p><strong>流量控制</strong>：流量控制在网络传输中是一个常用的概念，它用于调整网络包的数据。任意时间到来的请求往往是</p>
<p>随机不可控的，而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。</p>
<p><strong>熔断降级</strong>：当检测到调用链路中某个资源出现不稳定的表现，例如请求响应时间长或异常比例升高的时候，则</p>
<p>对这个资源的调用进行限制，让请求快速失败，避免影响到其它的资源而导致级联故障。</p>
<p><strong>系统负载保护</strong>：Sentinel 同时提供系统维度的自适应保护能力。当系统负载较高的时候，如果还持续让</p>
<p>请求进入可能会导致系统崩溃，无法响应。在集群环境下，会把本应这台机器承载的流量转发到其</p>
<p>它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候，Sentinel 提供了对应的保</p>
<p>护机制，让系统的入口流量和系统的负载达到一个平衡，保证系统在能力范围之内处理最多的请</p>
<p>求。</p>
<h3 id="646-sentinel规则种类">6.4.6 Sentinel规则种类</h3>
<p>Sentinel主要提供了这五种的流量控制，接下来我们每种都给同学们演示一下.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456727.png" alt="image-20201029160041081"></strong></p>
<h2 id="65-sentinel规则-流控">6.5 Sentinel规则-流控</h2>
<h3 id="651-流控规则">6.5.1 流控规则</h3>
<p>流量控制，其原理是监控应用流量的QPS(每秒查询率) 或并发线程数等指标，当达到指定的阈值时</p>
<p>对流量进行控制，以避免被瞬时的流量高峰冲垮，从而保障应用的高可用性。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456943.png" alt="image-20201029160919062"></strong></p>
<p><strong>资源名</strong>：唯一名称，默认是请求路径，可自定义</p>
<p><strong>针对来源</strong>：指定对哪个微服务进行限流，默认指default，意思是不区分来源，全部限制</p>
<p><strong>阈值类型/单机阈值</strong>：</p>
<ul>
<li>
<p>QPS（每秒请求数量）: 当调用该接口的QPS达到阈值的时候，进行限流</p>
</li>
<li>
<p>线程数：当调用该接口的线程数达到阈值的时候，进行限流</p>
</li>
</ul>
<p><strong>是否集群</strong>：暂不需要集群</p>
<h4 id="6511-qps流控">6.5.1.1 QPS流控</h4>
<p>前面6.4.4案例就是演示的QPS流控</p>
<h4 id="6512-线程数流控">6.5.1.2 线程数流控</h4>
<ol>
<li>
<p>删除掉之前的QPS流控，新增线程数流控</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457802.png" alt="image-20201029162926422"></strong></p>
</li>
<li>
<p>在Jmeter中新增线程</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457232.png" alt="image-20201029163205306"></strong></p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457758.png" alt="image-20201029163233714"></strong></p>
</li>
<li>
<p>访问 http://localhost:8091/sentinel2 会发现已经被限流</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457677.png" alt="image-20201029163416823"></strong></p>
</li>
</ol>
<h3 id="652-流控模式">6.5.2 流控模式</h3>
<p>点击上面设置流控规则的<strong>编辑</strong>按钮，然后在编辑页面点击<strong>高级选项</strong>，会看到有流控模式一栏。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457603.png" alt="image-20201029164212597"></strong></p>
<p>sentinel共有三种流控模式，分别是：</p>
<ul>
<li>
<p>直接（默认）：接口达到限流条件时，开启限流</p>
</li>
<li>
<p>关联：当关联的资源达到限流条件时，开启限流 [适合做应用让步]</p>
</li>
<li>
<p>链路：当从某个接口过来的资源达到限流条件时，开启限流</p>
</li>
</ul>
<h4 id="6521-直接流控模式">6.5.2.1 直接流控模式</h4>
<p>前面演示的案例就是这种.</p>
<h4 id="6522-关联流控模式">6.5.2.2 关联流控模式</h4>
<p>关联流控模式指的是，当指定接口关联的接口达到限流条件时，开启对指定接口开启限流。</p>
<p><strong>场景</strong>:当两个资源之间具有资源争抢或者依赖关系的时候，这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢，读的速度过高会影响写得速度，写的速度过高会影响读的速度。如果放任读写操作争抢资源，则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢.</p>
<ol>
<li>
<p>在SentinelController.java中增加一个方法，重启订单服务</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/sentinel3&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">sentinel3</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;sentinel3&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>配置限流规则, 将流控模式设置为关联，关联资源设置为的 /sentinel2</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457632.png" alt="image-20201029170800980"></strong></p>
</li>
<li>
<p>通过postman软件向/sentinel2连续发送请求，注意QPS一定要大于3</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457256.png" alt="image-20201029171026368"></strong></p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457680.png" alt="image-20201029171055757"></strong></p>
</li>
<li>
<p>访问/sentinel3,会发现已经被限流</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457129.png" alt="image-20201029171402061"></strong></p>
</li>
</ol>
<h4 id="6523-链路流控模式">6.5.2.3 链路流控模式</h4>
<p>链路流控模式指的是，当从某个接口过来的资源达到限流条件时，开启限流。</p>
<ol>
<li>
<p>在shop-order-server项目的application.yml文件中新增如下配置:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">sentinel</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">web-context-unify</span>: <span style="color:#66d9ef">false</span>
</span></span></code></pre></div></li>
<li>
<p>在shop-order-server项目中新增TraceServiceImpl.java</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.service.impl<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Service</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TraceServiceImpl</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@SentinelResource</span><span style="color:#f92672">(</span>value <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;tranceService&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">tranceService</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;调用tranceService方法&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>在shop-order-server项目中新增TraceController.java</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.controller<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TraceController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> TraceServiceImpl traceService<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/trace1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">trace1</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        traceService<span style="color:#f92672">.</span><span style="color:#a6e22e">tranceService</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;trace1&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/trace2&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">trace2</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        traceService<span style="color:#f92672">.</span><span style="color:#a6e22e">tranceService</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;trace2&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>重新启动订单服务并添加链路流控规则</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457036.png" alt="image-20201029175454431"></strong></p>
</li>
<li>
<p>分别通过 /trace1 和 /trace2 访问, 发现/trace1没问题, /trace2的被限流了</p>
</li>
</ol>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457302.png" alt="image-20201029175555499"></strong></p>
<h3 id="653-流控效果">6.5.3 流控效果</h3>
<ul>
<li>
<p><strong>快速失败（默认）</strong>: 直接失败，抛出异常，不做任何额外的处理，是最简单的效果</p>
</li>
<li>
<p><strong>Warm Up</strong>：它从开始阈值到最大QPS阈值会有一个缓冲阶段，一开始的阈值是最大QPS阈值的1/3，然后慢慢增长，直到最大阈值，适用于将突然增大的流量转换为缓步增长的场景。</p>
</li>
<li>
<p><strong>排队等待</strong>：让请求以均匀的速度通过，单机阈值为每秒通过数量，其余的排队等待； 它还会让设置一个超时时间，当请求超过超时间时间还未处理，则会被丢弃。</p>
</li>
</ul>
<h2 id="66-sentinel规则-降级">6.6 Sentinel规则-降级</h2>
<p>降级规则就是设置当满足什么条件的时候，对服务进行降级。Sentinel提供了三个衡量条件：</p>
<ul>
<li><strong>慢调用比例</strong>: 选择以慢调用比例作为阈值，需要设置允许的慢调用 RT（即最大的响应时间），请求的响应时间大于该值则统计为慢调用。当单位统计时长内请求数目大于设置的最小请求数目，并且慢调用的比例大于阈值，则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态（HALF-OPEN 状态），若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断，若大于设置的慢调用 RT 则会再次被熔断。</li>
<li><strong>异常比例</strong>: 当单位统计时长内请求数目大于设置的最小请求数目，并且异常的比例大于阈值，则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态（HALF-OPEN 状态），若接下来的一个请求成功完成（没有错误）则结束熔断，否则会再次被熔断。异常比率的阈值范围是 <code>[0.0, 1.0]</code>，代表 0% - 100%。</li>
<li><strong>异常数</strong>：当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态（HALF-OPEN 状态），若接下来的一个请求成功完成（没有错误）则结束熔断，否则会再次被熔断。</li>
</ul>
<h3 id="661-慢调用比例案例">6.6.1 慢调用比例案例</h3>
<ol>
<li>
<p>在shop-order-server项目中新增FallBackController.java类,代码如下:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.controller<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">FallBackController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/fallBack1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">fallBack1</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;fallBack1执行业务逻辑&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">//模拟业务耗时
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>            TimeUnit<span style="color:#f92672">.</span><span style="color:#a6e22e">SECONDS</span><span style="color:#f92672">.</span><span style="color:#a6e22e">sleep</span><span style="color:#f92672">(</span>1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span> <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>InterruptedException e<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            e<span style="color:#f92672">.</span><span style="color:#a6e22e">printStackTrace</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;fallBack1&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>新增降级规则:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457989.png" alt="image-20201030094205307"></strong></p>
<p>上面配置表示，如果在1S之内,有【超过1个的请求】且这些请求中【响应时间&gt;最大RT】的【请求数量比例&gt;10%】，就会触发熔断，在接下来的10s之内都不会调用真实方法，直接走降级方法。</p>
<p>比如: 最大RT=900,比例阈值=0.1,熔断时长=10,最小请求数=10</p>
<ul>
<li>
<p>情况1: 1秒内的有20个请求，只有10个请求响应时间&gt;900ms, 那慢调用比例=0.5，这种情况就会触发熔断</p>
</li>
<li>
<p>情况2: 1秒内的有20个请求，只有1个请求响应时间&gt;900ms, 那慢调用比例=0.05，这种情况不会触发熔断</p>
</li>
<li>
<p>情况3: 1秒内的有8个请求，只有6个请求响应时间&gt;900ms, 那慢调用比例=0.75，这种情况不会触发熔断，因为最小请求数这个条件没有满足.</p>
</li>
</ul>
<p><strong>注意</strong>: 我们做实验的时候把最小请求数设置为1，因为在1秒内，手动操作很难在1s内发两个请求过去，所以要做出效果,最好把最小请求数设置为1。</p>
</li>
</ol>
<h3 id="662-异常比例案例">6.6.2 异常比例案例</h3>
<ol>
<li>
<p>在shop-order-server项目的FallBackController.java类新增fallBack2方法:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">int</span> i<span style="color:#f92672">=</span>0<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/fallBack2&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">fallBack2</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>	log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;fallBack2执行业务逻辑&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">//模拟出现异常，异常比例为33%
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">if</span><span style="color:#f92672">(++</span>i<span style="color:#f92672">%</span>3<span style="color:#f92672">==</span>0<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> RuntimeException<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;fallBack2&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>新增降级规则:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457179.png" alt="image-20201030100912417"></strong></p>
<p>上面配置表示，在1s之内，,有【超过3个的请求】，异常比例30%的情况下，触发熔断，熔断时长为10s.</p>
</li>
</ol>
<h3 id="633-异常数案例">6.3.3 异常数案例</h3>
<ol>
<li>
<p>在shop-order-server项目的FallBackController.java类新增fallBack3方法:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/fallBack3&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">fallBack3</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>	log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;fallBack3执行业务逻辑&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;czh0123&#34;</span><span style="color:#f92672">.</span><span style="color:#a6e22e">equals</span><span style="color:#f92672">(</span>name<span style="color:#f92672">)){</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> RuntimeException<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;fallBack3&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>新增降级规则</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458459.png" alt="image-20201030102109574"></strong></p>
<p>上面配置表示，在1s之内，,有【超过3个的请求】，请求中超过2个请求出现异常就会触发熔断，熔断时长为10s</p>
</li>
</ol>
<h2 id="67-sentinel规则-热点">6.7 Sentinel规则-热点</h2>
<p>何为热点？热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据，并对其访问进行限制。比如：</p>
<ul>
<li>商品 ID 为参数，统计一段时间内最常购买的商品 ID 并进行限制</li>
<li>用户 ID 为参数，针对一段时间内频繁访问的用户 ID 进行限制</li>
</ul>
<p>热点参数限流会统计传入参数中的热点参数，并根据配置的限流阈值与模式，对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制，仅对包含热点参数的资源调用生效。</p>
<ol>
<li>
<p>在shop-order-server项目中新增HotSpotController.java,代码如下:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.controller<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">HotSpotController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/hotSpot1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@SentinelResource</span><span style="color:#f92672">(</span>value <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;hotSpot1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">hotSpot1</span><span style="color:#f92672">(</span>Long productId<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;访问编号为:{}的商品&#34;</span><span style="color:#f92672">,</span>productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;hotSpot1&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>注意:一定需要在请求方法上贴@SentinelResource直接，否则热点规则无效</p>
</li>
<li>
<p>新增热点规则:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458973.png" alt="image-20201030104511784"></strong></p>
</li>
<li>
<p>在热点规则中编辑规则,在编辑之前一定要先访问一下/hotSpot1,不然参数规则无法新增.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458826.png" alt="image-20201030104633745"></strong></p>
</li>
<li>
<p>新增参数规则:</p>
<p><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458326.png" alt="1625630523922"></p>
</li>
<li>
<p>点击保存，可以看到已经新增了参数规则.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458204.png" alt="image-20201030104957789"></strong></p>
</li>
<li>
<p>访问http://localhost:8091/hotSpot?productId=1 访问会降级</p>
<p>访问http://localhost:8091/hotSpot?productId=2 访问不会降级</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458253.png" alt="image-20201030105114878"></strong></p>
</li>
</ol>
<h2 id="68-sentinel规则-授权">6.8 Sentinel规则-授权</h2>
<p>很多时候，我们需要根据调用来源来判断该次请求是否允许放行，这时候可以使用 Sentinel 的来源访问控制（黑白名单控制）的功能。来源访问控制根据资源的请求来源（<code>origin</code>）限制资源是否通过，若配置白名单则只有请求来源位于白名单内时才可通过；若配置黑名单则请求来源位于黑名单时不通过，其余的请求通过。</p>
<ol>
<li>
<p>在shop-order-server中新建RequestOriginParserDefinition.java,定义请求来源如何获取</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@Component</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">RequestOriginParserDefinition</span> <span style="color:#66d9ef">implements</span> RequestOriginParser <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">parseOrigin</span><span style="color:#f92672">(</span>HttpServletRequest request<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">         *  定义从请求的什么地方获取来源信息
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">         *  比如我们可以要求所有的客户端需要在请求头中携带来源信息
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">         */</span>
</span></span><span style="display:flex;"><span>        String serviceName <span style="color:#f92672">=</span> request<span style="color:#f92672">.</span><span style="color:#a6e22e">getParameter</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;serviceName&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> serviceName<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>在shop-order-server中新建AuthController.java,代码如下:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AuthController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/auth1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">auth1</span><span style="color:#f92672">(</span>String serviceName<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;应用:{},访问接口&#34;</span><span style="color:#f92672">,</span>serviceName<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;auth1&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>新增授权规则</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458265.png" alt="image-20201030110821985"></strong></p>
</li>
<li>
<p>访问测试</p>
<p>访问http://localhost:8091/auth1?serviceName=pc 不能访问</p>
<p>访问http://localhost:8091/auth1?serviceName=app 可以访问</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458898.png" alt="image-20201030110934370"></strong></p>
</li>
</ol>
<h2 id="69-sentinel规则-系统规则">6.9 Sentinel规则-系统规则</h2>
<p>系统保护规则是从应用级别的入口流量进行控制，从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标，让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。</p>
<p>系统保护规则是应用整体维度的，而不是资源维度的，并且<strong>仅对入口流量生效</strong>。入口流量指的是进入应用的流量（<code>EntryType.IN</code>），比如 Web 服务或 Dubbo 服务端接收的请求，都属于入口流量。</p>
<p>系统规则支持以下的模式：</p>
<ul>
<li><strong>Load 自适应</strong>（仅对 Linux/Unix-like 机器生效）：系统的 load 作为启发指标，进行自适应系统保护。当系统 load 超过设定的启发值，且系统当前的并发线程数超过估算的系统容量时才会触发系统保护（BBR 阶段）。系统容量由系统的 <code>maxQps * minRt</code> 估算得出。设定参考值一般是 <code>CPU cores * 2.5</code>。</li>
<li><strong>CPU usage</strong>（1.5.0+ 版本）：当系统 CPU 使用率超过阈值即触发系统保护（取值范围 0.0-1.0），比较灵敏。</li>
<li><strong>平均 RT</strong>：当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护，单位是毫秒。</li>
<li><strong>并发线程数</strong>：当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。</li>
<li><strong>入口 QPS</strong>：当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。</li>
</ul>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458898.png" alt="image-20201030111407594"></strong></p>
<h2 id="610--sentinel-自定义异常返回">6.10  Sentinel 自定义异常返回</h2>
<p>当前面设定的规则没有满足是，我们可以自定义异常返回.</p>
<ul>
<li>
<p>FlowException 限流异常</p>
</li>
<li>
<p>DegradeException 降级异常</p>
</li>
<li>
<p>ParamFlowException 参数限流异常</p>
</li>
<li>
<p>AuthorityException 授权异常</p>
</li>
<li>
<p>SystemBlockException 系统负载异常</p>
</li>
</ul>
<p>在shop-order-server项目中定义异常返回处理类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.error<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Component</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ExceptionHandlerPage</span> <span style="color:#66d9ef">implements</span> BlockExceptionHandler <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">handle</span><span style="color:#f92672">(</span>HttpServletRequest request<span style="color:#f92672">,</span> HttpServletResponse response<span style="color:#f92672">,</span> BlockException e<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        response<span style="color:#f92672">.</span><span style="color:#a6e22e">setContentType</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;application/json;charset=utf-8&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        ResultData data <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>e <span style="color:#66d9ef">instanceof</span> FlowException<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            data <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ResultData<span style="color:#f92672">(-</span>1<span style="color:#f92672">,</span> <span style="color:#e6db74">&#34;接口被限流了&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span> <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>e <span style="color:#66d9ef">instanceof</span> DegradeException<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            data <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ResultData<span style="color:#f92672">(-</span>2<span style="color:#f92672">,</span> <span style="color:#e6db74">&#34;接口被降级了&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span><span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>e <span style="color:#66d9ef">instanceof</span> ParamFlowException<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            data <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ResultData<span style="color:#f92672">(-</span>3<span style="color:#f92672">,</span> <span style="color:#e6db74">&#34;参数限流异常&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span><span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>e <span style="color:#66d9ef">instanceof</span> AuthorityException<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            data <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ResultData<span style="color:#f92672">(-</span>4<span style="color:#f92672">,</span> <span style="color:#e6db74">&#34;授权异常&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span><span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>e <span style="color:#66d9ef">instanceof</span> SystemBlockException<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            data <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ResultData<span style="color:#f92672">(-</span>5<span style="color:#f92672">,</span> <span style="color:#e6db74">&#34;接口被降级了...&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        response<span style="color:#f92672">.</span><span style="color:#a6e22e">getWriter</span><span style="color:#f92672">().</span><span style="color:#a6e22e">write</span><span style="color:#f92672">(</span>JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>data<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Data</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@AllArgsConstructor</span><span style="color:#75715e">//全参构造
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">@NoArgsConstructor</span><span style="color:#75715e">//无参构造
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ResultData</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">int</span> code<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String message<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><h2 id="611-sentinelresource的使用">6.11 @SentinelResource的使用</h2>
<p>在定义了资源点之后，我们可以通过Dashboard来设置限流和降级策略来对资源点进行保护。同时还能</p>
<p>通过@SentinelResource来指定出现异常时的处理策略。</p>
<p>@SentinelResource 用于定义资源，并提供可选的异常处理和 fallback 配置项。</p>
<p>其主要参数如下:</p>
<table>
<thead>
<tr>
<th style="text-align:left">属性</th>
<th>作用</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">value</td>
<td>资源名称，必需项（不能为空）</td>
</tr>
<tr>
<td style="text-align:left">entryType</td>
<td>entry 类型，可选项（默认为 <code>EntryType.OUT</code>）</td>
</tr>
<tr>
<td style="text-align:left">blockHandler<code>/</code>blockHandlerClass</td>
<td><code>blockHandler</code> 对应处理 <code>BlockException</code> 的函数名称，可选项。blockHandler 函数访问范围需要是 <code>public</code>，返回类型需要与原方法相匹配，参数类型需要和原方法相匹配并且最后加一个额外的参数，类型为 <code>BlockException</code>。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数，则可以指定 <code>blockHandlerClass</code> 为对应的类的 <code>Class</code> 对象，注意对应的函数必需为 static 函数，否则无法解析。</td>
</tr>
<tr>
<td style="text-align:left">fallback<code>/</code>fallbackClass</td>
<td>fallback 函数名称，可选项，用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常（除了 <code>exceptionsToIgnore</code> 里面排除掉的异常类型）进行处理。fallback 函数签名和位置要求：<!-- raw HTML omitted -->1. 返回值类型必须与原函数返回值类型一致； <!-- raw HTML omitted -->2.方法参数列表需要和原函数一致，或者可以额外多一个 <code>Throwable</code> 类型的参数用于接收对应的异常。<!-- raw HTML omitted -->3.fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数，则可以指定 <code>fallbackClass</code> 为对应的类的 <code>Class</code> 对象，注意对应的函数必需为 static 函数，否则无法解析。</td>
</tr>
<tr>
<td style="text-align:left">defaultFallback</td>
<td>默认的 fallback 函数名称，可选项，通常用于通用的 fallback 逻辑（即可以用于很多服务或方法）。默认 fallback 函数可以针对所有类型的异常（除了 <code>exceptionsToIgnore</code> 里面排除掉的异常类型）进行处理。若同时配置了 fallback 和 defaultFallback，则只有 fallback 会生效。defaultFallback 函数签名要求：<!-- raw HTML omitted -->1. 返回值类型必须与原函数返回值类型一致；<!-- raw HTML omitted -->2. 方法参数列表需要为空，或者可以额外多一个 <code>Throwable</code> 类型的参数用于接收对应的异常。 <!-- raw HTML omitted -->3. defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数，则可以指定 <code>fallbackClass</code> 为对应的类的 <code>Class</code> 对象，注意对应的函数必需为 static 函数，否则无法解析。</td>
</tr>
<tr>
<td style="text-align:left">exceptionsToIgnore</td>
<td>用于指定哪些异常被排除掉，不会计入异常统计中，也不会进入 fallback 逻辑中，而是会原样抛出。</td>
</tr>
</tbody>
</table>
<p><strong>定义限流和降级后的处理方法</strong></p>
<p>直接将限流和降级方法定义在方法中</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.controller<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AnnoController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/anno1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@SentinelResource</span><span style="color:#f92672">(</span>value <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;anno1&#34;</span><span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            blockHandler<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;anno1BlockHandler&#34;</span><span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            fallback <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;anno1Fallback&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">anno1</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;czh0123&#34;</span><span style="color:#f92672">.</span><span style="color:#a6e22e">equals</span><span style="color:#f92672">(</span>name<span style="color:#f92672">)){</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> RuntimeException<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;anno1&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">anno1BlockHandler</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">,</span>BlockException ex<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">error</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;{}&#34;</span><span style="color:#f92672">,</span> ex<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;接口被限流或者降级了&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//Throwable时进入的方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">anno1Fallback</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">,</span>Throwable throwable<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">error</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;{}&#34;</span><span style="color:#f92672">,</span> throwable<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;接口发生异常了&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><h2 id="612-sentinel规则持久化">6.12 Sentinel规则持久化</h2>
<p>​	通过前面的讲解，我们已经知道，可以通过Dashboard来为每个Sentinel客户端设置各种各样的规</p>
<p>则，但是这里有一个问题，就是这些规则默认是存放在内存中，极不稳定，所以需要将其持久化。</p>
<p>​	本地文件数据源会定时轮询文件的变更，读取规则。这样我们既可以在应用本地直接修改文件来更</p>
<p>新规则，也可以通过 Sentinel 控制台推送规则。以本地文件数据源为例，推送过程如下图所示：</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111459121.png" alt="image-20201030135911029"></strong></p>
<p>首先 Sentinel 控制台通过 API 将规则推送至客户端并更新到内存中，接着注册的写数据源会将新的</p>
<p>规则保存到本地的文件中。</p>
<ol>
<li>
<p>编写处理类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.sentinel<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">FilePersistence</span> <span style="color:#66d9ef">implements</span> InitFunc <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Value</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;${spring.application.name}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String appcationName<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">init</span><span style="color:#f92672">()</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        String ruleDir <span style="color:#f92672">=</span> System<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;user.home&#34;</span><span style="color:#f92672">)</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/sentinel-rules/&#34;</span> <span style="color:#f92672">+</span> appcationName<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        String flowRulePath <span style="color:#f92672">=</span> ruleDir <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/flow-rule.json&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        String degradeRulePath <span style="color:#f92672">=</span> ruleDir <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/degrade-rule.json&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        String systemRulePath <span style="color:#f92672">=</span> ruleDir <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/system-rule.json&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        String authorityRulePath <span style="color:#f92672">=</span> ruleDir <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/authority-rule.json&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        String paramFlowRulePath <span style="color:#f92672">=</span> ruleDir <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/param-flow-rule.json&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">mkdirIfNotExits</span><span style="color:#f92672">(</span>ruleDir<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">createFileIfNotExits</span><span style="color:#f92672">(</span>flowRulePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">createFileIfNotExits</span><span style="color:#f92672">(</span>degradeRulePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">createFileIfNotExits</span><span style="color:#f92672">(</span>systemRulePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">createFileIfNotExits</span><span style="color:#f92672">(</span>authorityRulePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">createFileIfNotExits</span><span style="color:#f92672">(</span>paramFlowRulePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 流控规则
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ReadableDataSource<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>FlowRule<span style="color:#f92672">&gt;&gt;</span> flowRuleRDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileRefreshableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                flowRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                flowRuleListParser
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        FlowRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">register2Property</span><span style="color:#f92672">(</span>flowRuleRDS<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        WritableDataSource<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>FlowRule<span style="color:#f92672">&gt;&gt;</span> flowRuleWDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileWritableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                flowRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">this</span><span style="color:#f92672">::</span>encodeJson
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        WritableDataSourceRegistry<span style="color:#f92672">.</span><span style="color:#a6e22e">registerFlowDataSource</span><span style="color:#f92672">(</span>flowRuleWDS<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 降级规则
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ReadableDataSource<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>DegradeRule<span style="color:#f92672">&gt;&gt;</span> degradeRuleRDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileRefreshableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                degradeRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                degradeRuleListParser
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        DegradeRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">register2Property</span><span style="color:#f92672">(</span>degradeRuleRDS<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        WritableDataSource<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>DegradeRule<span style="color:#f92672">&gt;&gt;</span> degradeRuleWDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileWritableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                degradeRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">this</span><span style="color:#f92672">::</span>encodeJson
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        WritableDataSourceRegistry<span style="color:#f92672">.</span><span style="color:#a6e22e">registerDegradeDataSource</span><span style="color:#f92672">(</span>degradeRuleWDS<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 系统规则
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ReadableDataSource<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>SystemRule<span style="color:#f92672">&gt;&gt;</span> systemRuleRDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileRefreshableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                systemRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                systemRuleListParser
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        SystemRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">register2Property</span><span style="color:#f92672">(</span>systemRuleRDS<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        WritableDataSource<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>SystemRule<span style="color:#f92672">&gt;&gt;</span> systemRuleWDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileWritableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                systemRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">this</span><span style="color:#f92672">::</span>encodeJson
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        WritableDataSourceRegistry<span style="color:#f92672">.</span><span style="color:#a6e22e">registerSystemDataSource</span><span style="color:#f92672">(</span>systemRuleWDS<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 授权规则
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ReadableDataSource<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>AuthorityRule<span style="color:#f92672">&gt;&gt;</span> authorityRuleRDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileRefreshableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                authorityRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                authorityRuleListParser
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        AuthorityRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">register2Property</span><span style="color:#f92672">(</span>authorityRuleRDS<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        WritableDataSource<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>AuthorityRule<span style="color:#f92672">&gt;&gt;</span> authorityRuleWDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileWritableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                authorityRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">this</span><span style="color:#f92672">::</span>encodeJson
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        WritableDataSourceRegistry<span style="color:#f92672">.</span><span style="color:#a6e22e">registerAuthorityDataSource</span><span style="color:#f92672">(</span>authorityRuleWDS<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 热点参数规则
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ReadableDataSource<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>ParamFlowRule<span style="color:#f92672">&gt;&gt;</span> paramFlowRuleRDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileRefreshableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                paramFlowRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                paramFlowRuleListParser
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        ParamFlowRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">register2Property</span><span style="color:#f92672">(</span>paramFlowRuleRDS<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        WritableDataSource<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>ParamFlowRule<span style="color:#f92672">&gt;&gt;</span> paramFlowRuleWDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileWritableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                paramFlowRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">this</span><span style="color:#f92672">::</span>encodeJson
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        ModifyParamFlowRulesCommandHandler<span style="color:#f92672">.</span><span style="color:#a6e22e">setWritableDataSource</span><span style="color:#f92672">(</span>paramFlowRuleWDS<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Converter<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>FlowRule<span style="color:#f92672">&gt;&gt;</span> flowRuleListParser <span style="color:#f92672">=</span> source <span style="color:#f92672">-&gt;</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">parseObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>            source<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">new</span> TypeReference<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>FlowRule<span style="color:#f92672">&gt;&gt;()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Converter<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>DegradeRule<span style="color:#f92672">&gt;&gt;</span> degradeRuleListParser <span style="color:#f92672">=</span> source <span style="color:#f92672">-&gt;</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">parseObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>            source<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">new</span> TypeReference<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>DegradeRule<span style="color:#f92672">&gt;&gt;()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Converter<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>SystemRule<span style="color:#f92672">&gt;&gt;</span> systemRuleListParser <span style="color:#f92672">=</span> source <span style="color:#f92672">-&gt;</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">parseObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>            source<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">new</span> TypeReference<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>SystemRule<span style="color:#f92672">&gt;&gt;()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Converter<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>AuthorityRule<span style="color:#f92672">&gt;&gt;</span> authorityRuleListParser <span style="color:#f92672">=</span> source <span style="color:#f92672">-&gt;</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">parseObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>            source<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">new</span> TypeReference<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>AuthorityRule<span style="color:#f92672">&gt;&gt;()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Converter<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>ParamFlowRule<span style="color:#f92672">&gt;&gt;</span> paramFlowRuleListParser <span style="color:#f92672">=</span> source <span style="color:#f92672">-&gt;</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">parseObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>            source<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">new</span> TypeReference<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>ParamFlowRule<span style="color:#f92672">&gt;&gt;()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">mkdirIfNotExits</span><span style="color:#f92672">(</span>String filePath<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> IOException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        File file <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> File<span style="color:#f92672">(</span>filePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">(!</span>file<span style="color:#f92672">.</span><span style="color:#a6e22e">exists</span><span style="color:#f92672">())</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            file<span style="color:#f92672">.</span><span style="color:#a6e22e">mkdirs</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">createFileIfNotExits</span><span style="color:#f92672">(</span>String filePath<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> IOException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        File file <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> File<span style="color:#f92672">(</span>filePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">(!</span>file<span style="color:#f92672">.</span><span style="color:#a6e22e">exists</span><span style="color:#f92672">())</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            file<span style="color:#f92672">.</span><span style="color:#a6e22e">createNewFile</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#f92672">&lt;</span>T<span style="color:#f92672">&gt;</span> String <span style="color:#a6e22e">encodeJson</span><span style="color:#f92672">(</span>T t<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>t<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>添加配置</p>
<p>在<code>resources</code>下创建配置目录 <code>META-INF/services</code> ,然后添加文件 <code>com.alibaba.csp.sentinel.init.InitFunc</code></p>
<p>在文件中添加配置类的全路径</p>
<p><code>cn.czh0123.sentinel.FilePersistence</code></p>
</li>
</ol>
<h2 id="613-feign整合sentinel">6.13 Feign整合Sentinel</h2>
<ol>
<li>
<p>在shop-order-server项目的配置文件中开启feign对Sentinel的支持</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">feign</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">sentinel</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div></li>
<li>
<p>创建容错类</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@Component</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ProductFeignFallBack</span> <span style="color:#66d9ef">implements</span> ProductFeignApi <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Product <span style="color:#a6e22e">findByPid</span><span style="color:#f92672">(</span>Long pid<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Product product <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Product<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        product<span style="color:#f92672">.</span><span style="color:#a6e22e">setPid</span><span style="color:#f92672">(-</span>1L<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        product<span style="color:#f92672">.</span><span style="color:#a6e22e">setPname</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;兜底数据&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        product<span style="color:#f92672">.</span><span style="color:#a6e22e">setPprice</span><span style="color:#f92672">(</span>0<span style="color:#f92672">.</span><span style="color:#a6e22e">0</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> product<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><ol start="3">
<li>
<p>在feign接口中定义容错类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@FeignClient</span><span style="color:#f92672">(</span>name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;product-service&#34;</span><span style="color:#f92672">,</span>fallback <span style="color:#f92672">=</span> ProductFeignFallBack<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">ProductFeignApi</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/product/{pid}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Product <span style="color:#a6e22e">findByPid</span><span style="color:#f92672">(</span><span style="color:#a6e22e">@PathVariable</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;pid&#34;</span><span style="color:#f92672">)</span> Long pid<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>停止所有 商品服务,重启 shop-order 服务,访问请求,观察容错效果</p>
</li>
</ol>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111459330.png" alt="image-20201030141556327"></strong></p>
<p>可能上面的案例并不是特别恰当，我们只是通过案例来演示Feign集成Sentinel实现降级的效果. 接下来我们具体更贴切的案例来讲解Feign降级的作用.</p>
<p>比如我们在购物的时候，查看商品详情页面的时候，里面包含库存信息,商品详情信息,评论信息，这个需求包含的微服务如下:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111459887.png" alt="image-20201030142332530"></strong></p>
<p>假设现在评论服务宕机了,那是不是意味用户发出查看商品请求也无法正常显示了，商品都看不到了，那用户也无法进行下单的操作了. 但是对于用户来说，评论看不到并不影响他购物，所以这时候我们应该对评论服务进行及·降级处理，返回一个兜底数据(空数据)，这样用户的查看商品请求能正常显示，只是评论数据看不到而已，这样的话，用户的下单请求也不会受到影响.</p>
<h1 id="第七章-服务网关gateway">第七章 服务网关Gateway</h1>
<p>大家都都知道在微服务架构中，一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢？如果没有网关的存在，我们只能在客户端记录每个微服务的地址，然后分别去调用。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111459936.png" alt="image-20201030144013742"></strong></p>
<p>这样的架构，会存在着诸多的问题：</p>
<ul>
<li>
<p>客户端多次请求不同的微服务，增加客户端代码或配置编写的复杂性</p>
</li>
<li>
<p>认证复杂，每个服务都需要独立认证。</p>
</li>
<li>
<p>微服务做集群的情况下，客户端并没有负责均衡的功能</p>
</li>
</ul>
<p>上面的这些问题可以借助<strong>API网关</strong>来解决。</p>
<p>所谓的API网关，就是指系统的<strong>统一入口</strong>，它封装了应用程序的内部结构，为客户端提供统一服</p>
<p>务，一些与业务本身功能无关的公共逻辑可以在这里实现，诸如认证、鉴权、监控、路由转发等等。</p>
<p>添加上API网关之后，系统的架构图变成了如下所示：</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111459125.png" alt="image-20201030144534269"></strong></p>
<p>网关是如何知道微服务的地址?网关如何进行负载均衡呢？</p>
<p>网关需要将自己的信息注册到注册中心上并且拉取其他微服务的信息，然后再调用的时候基于Ribbon实现负载均衡</p>
<h2 id="71-常见网关介绍">7.1 常见网关介绍</h2>
<ul>
<li><strong>Ngnix+lua</strong></li>
</ul>
<p>使用nginx的反向代理和负载均衡可实现对api服务器的负载均衡及高可用,lua是一种脚本语言,可以来编写一些简单的逻辑, nginx支持lua脚本</p>
<ul>
<li><strong>Kong</strong></li>
</ul>
<p>基于Nginx+Lua开发，性能高，稳定，有多个可用的插件(限流、鉴权等等)可以开箱即用。 问题：只支持Http协议；二次开发，自由扩展困难；提供管理API，缺乏更易用的管控、配置方式。</p>
<ul>
<li><strong>Zuul</strong></li>
</ul>
<p>Netflflix开源的网关，功能丰富，使用JAVA开发，易于二次开发 问题：缺乏管控，无法动态配置；依赖组件较多；处理Http请求依赖的是Web容器，性能不如Nginx,Spring Cloud Gateway</p>
<p>Spring公司为了替换Zuul而开发的网关服务，将在下面具体介绍。</p>
<p>注意：SpringCloud alibaba技术栈中并没有提供自己的网关，我们可以采用Spring Cloud Gateway</p>
<p>来做网关</p>
<h2 id="72-gateway简介">7.2 Gateway简介</h2>
<p>​	Spring Cloud Gateway是Spring公司基于Spring 5.0，Spring Boot 2.0 和 Project Reactor 等技术开发的网关，它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。它的目标是替代</p>
<p>Netflflix Zuul，其不仅提供统一的路由方式，并且基于 Filter 链的方式提供了网关基本的功能，例如：安</p>
<p>全，监控和限流。</p>
<p><strong>优点：</strong></p>
<ul>
<li>
<p>性能强劲：是第一代网关Zuul的1.6倍</p>
</li>
<li>
<p>功能强大：内置了很多实用的功能，例如转发、监控、限流等</p>
</li>
<li>
<p>设计优雅，容易扩展</p>
</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li>
<p>其实现依赖Netty与WebFlux，不是传统的Servlet编程模型，学习成本高</p>
</li>
<li>
<p>不能将其部署在Tomcat、Jetty等Servlet容器里，只能打成jar包执行</p>
</li>
<li>
<p>需要Spring Boot 2.0及以上的版本，才支持</p>
</li>
</ul>
<h2 id="73-gateway快速入门">7.3 Gateway快速入门</h2>
<ol>
<li>
<p>创建一个 api-gateway 的模块,导入相关依赖</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#75715e">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;project</span> <span style="color:#a6e22e">xmlns=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xmlns:xsi=</span><span style="color:#e6db74">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xsi:schemaLocation=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;parent&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;artifactId&gt;</span>shop-parent<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;groupId&gt;</span>cn.czh0123<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;version&gt;</span>1.0.0<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/parent&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;modelVersion&gt;</span>4.0.0<span style="color:#f92672">&lt;/modelVersion&gt;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;artifactId&gt;</span>api-gateway<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;dependencies&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">&lt;!--gateway网关--&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>org.springframework.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-starter-gateway<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">&lt;!--nacos客户端--&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>com.alibaba.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-starter-alibaba-nacos-discovery<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>org.projectlombok<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>lombok<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/dependencies&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/project&gt;</span>
</span></span></code></pre></div></li>
<li>
<p>编写启动类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@SpringBootApplication</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@EnableDiscoveryClient</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ApiGatewayServer</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        SpringApplication<span style="color:#f92672">.</span><span style="color:#a6e22e">run</span><span style="color:#f92672">(</span>ApiGatewayServer<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">,</span>args<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>编写配置文件</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">server</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">port</span>: <span style="color:#ae81ff">9000</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">application</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">api-gateway</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">nacos</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">discovery</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">server-addr</span>: <span style="color:#ae81ff">localhost:8848</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">gateway</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">discovery</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">locator</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span> <span style="color:#75715e"># 让gateway可以发现nacos中的微服务</span>
</span></span></code></pre></div></li>
<li>
<p>启动测试</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111500669.png" alt="image-20201030152917728"></strong></p>
</li>
</ol>
<h2 id="74-自定义路由规则">7.4 自定义路由规则</h2>
<ol>
<li>
<p>在application.yml中添加新的路由规则</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">gateway</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">routes</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">id</span>: <span style="color:#ae81ff">product_route</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">uri</span>: <span style="color:#ae81ff">lb://product-service </span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">predicates</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">Path=/product-serv/**</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">filters</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">StripPrefix=1</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">id</span>: <span style="color:#ae81ff">order_route</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">uri</span>: <span style="color:#ae81ff">lb://order-service </span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">predicates</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">Path=/order-serv/**</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">filters</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">StripPrefix=1</span>
</span></span></code></pre></div></li>
<li>
<p>启动测试</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111500971.png" alt="image-20201030154027833"></strong></p>
</li>
</ol>
<h2 id="75-gateway概念">7.5 Gateway概念</h2>
<p>路由(Route) 是 gateway 中最基本的组件之一，表示一个具体的路由信息载体。主要定义了下面的几个</p>
<p>信息:</p>
<ul>
<li>
<p><strong>id</strong>，路由标识符，区别于其他 Route。</p>
</li>
<li>
<p><strong>uri</strong>，路由指向的目的地 uri，即客户端请求最终被转发到的微服务。</p>
</li>
<li>
<p><strong>order</strong>，用于多个 Route 之间的排序，数值越小排序越靠前，匹配优先级越高。</p>
</li>
<li>
<p><strong>predicate</strong>，断言的作用是进行条件判断，只有断言都返回真，才会真正的执行路由。</p>
</li>
<li>
<p><strong>filter</strong>，过滤器用于修改请求和响应信息。</p>
</li>
</ul>
<p>执行流程图:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111500962.png" alt="image-20201030161652819"></strong></p>
<h2 id="76-过滤器filter">7.6 过滤器Filter</h2>
<p>过滤器就是在请求的传递过程中,对请求和响应做一些手脚.</p>
<p>在Gateway中, Filter的生命周期只有两个：“pre” 和 “post”。</p>
<ul>
<li>
<p>PRE： 这种过滤器在请求到调用的业务服务之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。</p>
</li>
<li>
<p>POST：这种过滤器在访问到微服务以后执行。这种过滤器可用来为响应添加标准的HTTPHeader、收集统计信息和指标、将响应从微服务发送给客户端等。</p>
</li>
</ul>
<p>在Gateway中，Filter的作用范围两种:</p>
<ul>
<li>
<p>GatewayFilter：应用到单个路由或者一个分组的路由上。</p>
</li>
<li>
<p>GlobalFilter：应用到所有的路由上</p>
</li>
</ul>
<h3 id="761-局部路由过滤器">7.6.1 局部路由过滤器</h3>
<p>局部过滤器是针对单个路由的过滤器,在SpringCloud Gateway中内置了很多不同类型的网关路由过滤器,有兴趣同学可以自行了解，这里太多了，我们就不一一讲解，我们主要来讲一下自定义路由过滤器。</p>
<p>需求: 统计订单服务调用耗时.</p>
<ol>
<li>
<p>编写Filter类，注意名称是有固定格式xxxGatewayFilterFactory</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.filters<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Component</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TimeGatewayFilterFactory</span> <span style="color:#66d9ef">extends</span> AbstractGatewayFilterFactory<span style="color:#f92672">&lt;</span>TimeGatewayFilterFactory<span style="color:#f92672">.</span><span style="color:#a6e22e">Config</span><span style="color:#f92672">&gt;{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> String BEGIN_TIME <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;beginTime&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//构造函数
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">TimeGatewayFilterFactory</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">super</span><span style="color:#f92672">(</span>TimeGatewayFilterFactory<span style="color:#f92672">.</span><span style="color:#a6e22e">Config</span><span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//读取配置文件中的参数 赋值到 配置类中
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> List<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">&gt;</span> <span style="color:#a6e22e">shortcutFieldOrder</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> Arrays<span style="color:#f92672">.</span><span style="color:#a6e22e">asList</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;show&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> GatewayFilter <span style="color:#a6e22e">apply</span><span style="color:#f92672">(</span>Config config<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> GatewayFilter<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">public</span> Mono<span style="color:#f92672">&lt;</span>Void<span style="color:#f92672">&gt;</span> <span style="color:#a6e22e">filter</span><span style="color:#f92672">(</span>ServerWebExchange exchange<span style="color:#f92672">,</span> GatewayFilterChain chain<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">if</span><span style="color:#f92672">(!</span>config<span style="color:#f92672">.</span><span style="color:#a6e22e">show</span><span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#66d9ef">return</span> chain<span style="color:#f92672">.</span><span style="color:#a6e22e">filter</span><span style="color:#f92672">(</span>exchange<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>                exchange<span style="color:#f92672">.</span><span style="color:#a6e22e">getAttributes</span><span style="color:#f92672">().</span><span style="color:#a6e22e">put</span><span style="color:#f92672">(</span>BEGIN_TIME<span style="color:#f92672">,</span> System<span style="color:#f92672">.</span><span style="color:#a6e22e">currentTimeMillis</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>                <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                 *  pre的逻辑
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                 * chain.filter().then(Mono.fromRunable(()-&gt;{
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                 *     post的逻辑
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                 * }))
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                 */</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">return</span> chain<span style="color:#f92672">.</span><span style="color:#a6e22e">filter</span><span style="color:#f92672">(</span>exchange<span style="color:#f92672">).</span><span style="color:#a6e22e">then</span><span style="color:#f92672">(</span>Mono<span style="color:#f92672">.</span><span style="color:#a6e22e">fromRunnable</span><span style="color:#f92672">(()-&gt;{</span>
</span></span><span style="display:flex;"><span>                    Long startTime <span style="color:#f92672">=</span> exchange<span style="color:#f92672">.</span><span style="color:#a6e22e">getAttribute</span><span style="color:#f92672">(</span>BEGIN_TIME<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>startTime <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>exchange<span style="color:#f92672">.</span><span style="color:#a6e22e">getRequest</span><span style="color:#f92672">().</span><span style="color:#a6e22e">getURI</span><span style="color:#f92672">()</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;请求耗时: &#34;</span> <span style="color:#f92672">+</span> <span style="color:#f92672">(</span>System<span style="color:#f92672">.</span><span style="color:#a6e22e">currentTimeMillis</span><span style="color:#f92672">()</span> <span style="color:#f92672">-</span> startTime<span style="color:#f92672">)</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;ms&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">}));</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">};</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Setter@Getter</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Config</span><span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">boolean</span> show<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>在指定的路由中添加路由规则</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">server</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">port</span>: <span style="color:#ae81ff">9000</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">application</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">api-gateway</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">nacos</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">discovery</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">server-addr</span>: <span style="color:#ae81ff">localhost:8848</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">gateway</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">discovery</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">locator</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span> 
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">routes</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">id</span>: <span style="color:#ae81ff">product_route</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">uri</span>: <span style="color:#ae81ff">lb://product-service </span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">predicates</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">Path=/product-serv/**</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">filters</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">StripPrefix=1</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">id</span>: <span style="color:#ae81ff">order_route</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">uri</span>: <span style="color:#ae81ff">lb://order-service </span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">predicates</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">Path=/order-serv/**</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">filters</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">StripPrefix=1</span>
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">Time=true</span>
</span></span></code></pre></div></li>
<li>
<p>访问商品服务的时候是没有打印日志的，访问订单服务的时候打印入职如下:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111500447.png" alt="image-20201030171007704"></strong></p>
</li>
</ol>
<h3 id="762-全局路由过滤器">7.6.2 全局路由过滤器</h3>
<p>全局过滤器作用于所有路由, 无需配置。通过全局过滤器可以实现对权限的统一校验，安全性验证等功</p>
<p>能。</p>
<p>SpringCloud Gateway内部也是通过一系列的内置全局过滤器对整个路由转发进行处理如下：</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111500984.jpg" alt=""></strong></p>
<p>需求: 实现统一鉴权的功能,我们需要在网关判断请求中是否包含token且，如果没有则不转发路由，有则执行正常逻辑。</p>
<ol>
<li>
<p>编写全局过滤类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.filters<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Component</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AuthGlobalFilter</span> <span style="color:#66d9ef">implements</span> GlobalFilter <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Mono<span style="color:#f92672">&lt;</span>Void<span style="color:#f92672">&gt;</span> <span style="color:#a6e22e">filter</span><span style="color:#f92672">(</span>ServerWebExchange exchange<span style="color:#f92672">,</span> GatewayFilterChain chain<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        String token <span style="color:#f92672">=</span> exchange<span style="color:#f92672">.</span><span style="color:#a6e22e">getRequest</span><span style="color:#f92672">().</span><span style="color:#a6e22e">getQueryParams</span><span style="color:#f92672">().</span><span style="color:#a6e22e">getFirst</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;token&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>StringUtils<span style="color:#f92672">.</span><span style="color:#a6e22e">isBlank</span><span style="color:#f92672">(</span>token<span style="color:#f92672">))</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;鉴权失败&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            exchange<span style="color:#f92672">.</span><span style="color:#a6e22e">getResponse</span><span style="color:#f92672">().</span><span style="color:#a6e22e">setStatusCode</span><span style="color:#f92672">(</span>HttpStatus<span style="color:#f92672">.</span><span style="color:#a6e22e">UNAUTHORIZED</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> exchange<span style="color:#f92672">.</span><span style="color:#a6e22e">getResponse</span><span style="color:#f92672">().</span><span style="color:#a6e22e">setComplete</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> chain<span style="color:#f92672">.</span><span style="color:#a6e22e">filter</span><span style="color:#f92672">(</span>exchange<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>启动并测试</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111501855.png" alt="image-20201030172557201"></strong></p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111501890.png" alt="image-20201030172635132"></strong></p>
</li>
</ol>
<h2 id="77-集成sentinel实现网关限流">7.7 集成Sentinel实现网关限流</h2>
<p>网关是所有请求的公共入口，所以可以在网关进行限流，而且限流的方式也很多，我们本次采用前面学过的Sentinel组件来实现网关的限流。Sentinel支持对SpringCloud Gateway、Zuul等主流网关进行限流。</p>
<p>从1.6.0版本开始，Sentinel提供了SpringCloud Gateway的适配模块，可以提供两种资源维度的限流：</p>
<ul>
<li>
<p>route维度：即在Spring配置文件中配置的路由条目，资源名为对应的routeId</p>
</li>
<li>
<p>自定义API维度：用户可以利用Sentinel提供的API来自定义一些API分组</p>
</li>
</ul>
<h3 id="771-网关集成sentinel">7.7.1 网关集成Sentinel</h3>
<p><a href="https://github.com/alibaba/Sentinel/wiki/">https://github.com/alibaba/Sentinel/wiki/</a>网关限流</p>
<ol>
<li>
<p>添加依赖</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;groupId&gt;</span>com.alibaba.csp<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;artifactId&gt;</span>sentinel-spring-cloud-gateway-adapter<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span></code></pre></div></li>
<li>
<p>编写配置类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>    <span style="color:#f92672">package</span> cn.czh0123.config<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Configuration</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">GatewayConfiguration</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">final</span> List<span style="color:#f92672">&lt;</span>ViewResolver<span style="color:#f92672">&gt;</span> viewResolvers<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">final</span> ServerCodecConfigurer serverCodecConfigurer<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">GatewayConfiguration</span><span style="color:#f92672">(</span>ObjectProvider<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>ViewResolver<span style="color:#f92672">&gt;&gt;</span> viewResolversProvider<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                                    ServerCodecConfigurer serverCodecConfigurer<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">viewResolvers</span> <span style="color:#f92672">=</span> viewResolversProvider<span style="color:#f92672">.</span><span style="color:#a6e22e">getIfAvailable</span><span style="color:#f92672">(</span>Collections<span style="color:#f92672">::</span>emptyList<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">serverCodecConfigurer</span> <span style="color:#f92672">=</span> serverCodecConfigurer<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 配置限流的异常处理器
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#a6e22e">@Bean</span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">@Order</span><span style="color:#f92672">(</span>Ordered<span style="color:#f92672">.</span><span style="color:#a6e22e">HIGHEST_PRECEDENCE</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> SentinelGatewayBlockExceptionHandler <span style="color:#a6e22e">sentinelGatewayBlockExceptionHandler</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">// Register the block exception handler for Spring Cloud Gateway.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>            <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> SentinelGatewayBlockExceptionHandler<span style="color:#f92672">(</span>viewResolvers<span style="color:#f92672">,</span> serverCodecConfigurer<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 初始化一个限流的过滤器
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#a6e22e">@Bean</span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">@Order</span><span style="color:#f92672">(</span>Ordered<span style="color:#f92672">.</span><span style="color:#a6e22e">HIGHEST_PRECEDENCE</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> GlobalFilter <span style="color:#a6e22e">sentinelGatewayFilter</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> SentinelGatewayFilter<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//增加对商品微服务的 限流
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>         <span style="color:#a6e22e">@PostConstruct</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">initGatewayRules</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            Set<span style="color:#f92672">&lt;</span>GatewayFlowRule<span style="color:#f92672">&gt;</span> rules <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> HashSet<span style="color:#f92672">&lt;&gt;();</span>
</span></span><span style="display:flex;"><span>            rules<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> GatewayFlowRule<span style="color:#f92672">(</span><span style="color:#e6db74">&#34;product_route&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">.</span><span style="color:#a6e22e">setCount</span><span style="color:#f92672">(</span>3<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">.</span><span style="color:#a6e22e">setIntervalSec</span><span style="color:#f92672">(</span>1<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            GatewayRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">loadRules</span><span style="color:#f92672">(</span>rules<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>重启网关服务并测试.</p>
</li>
</ol>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111501522.png" alt="image-20201030175846125"></strong></p>
<h3 id="772-修改限流默认返回格式">7.7.2 修改限流默认返回格式</h3>
<ol>
<li>
<p>在配置类GatewayConfiguration.java中添加如下配置</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@PostConstruct</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">initBlockHandlers</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>	BlockRequestHandler blockRequestHandler <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> BlockRequestHandler<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">public</span> Mono<span style="color:#f92672">&lt;</span>ServerResponse<span style="color:#f92672">&gt;</span> <span style="color:#a6e22e">handleRequest</span><span style="color:#f92672">(</span>ServerWebExchange serverWebExchange<span style="color:#f92672">,</span> Throwable throwable<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>		Map map <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> HashMap<span style="color:#f92672">&lt;&gt;();</span>
</span></span><span style="display:flex;"><span>		map<span style="color:#f92672">.</span><span style="color:#a6e22e">put</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;code&#34;</span><span style="color:#f92672">,</span> 0<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>		map<span style="color:#f92672">.</span><span style="color:#a6e22e">put</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;message&#34;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#34;接口被限流了&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> ServerResponse<span style="color:#f92672">.</span><span style="color:#a6e22e">status</span><span style="color:#f92672">(</span>HttpStatus<span style="color:#f92672">.</span><span style="color:#a6e22e">OK</span><span style="color:#f92672">).</span>
</span></span><span style="display:flex;"><span>				contentType<span style="color:#f92672">(</span>MediaType<span style="color:#f92672">.</span><span style="color:#a6e22e">APPLICATION_JSON</span><span style="color:#f92672">).</span>
</span></span><span style="display:flex;"><span>				body<span style="color:#f92672">(</span>BodyInserters<span style="color:#f92672">.</span><span style="color:#a6e22e">fromValue</span><span style="color:#f92672">(</span>map<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">};</span>
</span></span><span style="display:flex;"><span>	GatewayCallbackManager<span style="color:#f92672">.</span><span style="color:#a6e22e">setBlockHandler</span><span style="color:#f92672">(</span>blockRequestHandler<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>重启并测试</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111501478.png" alt="image-20201030180400822"></strong></p>
</li>
</ol>
<h3 id="773-自定义api分组">7.7.3 自定义API分组</h3>
<p>自定义API分组是一种更细粒度的限流规则定义</p>
<ol>
<li>
<p>在shop-order-server项目中添加ApiController</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.controller<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/api&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ApiController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/hello&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">api1</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;api&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>重启shop-order-server项目.</p>
</li>
<li>
<p>在api-gateway项目的配置GatewayConfiguration.java中添加如下配置:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@PostConstruct</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">initCustomizedApis</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>	Set<span style="color:#f92672">&lt;</span>ApiDefinition<span style="color:#f92672">&gt;</span> definitions <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> HashSet<span style="color:#f92672">&lt;&gt;();</span>
</span></span><span style="display:flex;"><span>	ApiDefinition api1 <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ApiDefinition<span style="color:#f92672">(</span><span style="color:#e6db74">&#34;order_api&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">setPredicateItems</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> HashSet<span style="color:#f92672">&lt;</span>ApiPredicateItem<span style="color:#f92672">&gt;()</span> <span style="color:#f92672">{{</span>
</span></span><span style="display:flex;"><span>                    add<span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> ApiPathPredicateItem<span style="color:#f92672">().</span><span style="color:#a6e22e">setPattern</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/order-serv/api/**&#34;</span><span style="color:#f92672">).</span>                 setMatchStrategy<span style="color:#f92672">(</span>SentinelGatewayConstants<span style="color:#f92672">.</span><span style="color:#a6e22e">URL_MATCH_STRATEGY_PREFIX</span><span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">}});</span>
</span></span><span style="display:flex;"><span>	definitions<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span>api1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>	GatewayApiDefinitionManager<span style="color:#f92672">.</span><span style="color:#a6e22e">loadApiDefinitions</span><span style="color:#f92672">(</span>definitions<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@PostConstruct</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">initGatewayRules</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>	Set<span style="color:#f92672">&lt;</span>GatewayFlowRule<span style="color:#f92672">&gt;</span> rules <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> HashSet<span style="color:#f92672">&lt;&gt;();</span>
</span></span><span style="display:flex;"><span>	rules<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> GatewayFlowRule<span style="color:#f92672">(</span><span style="color:#e6db74">&#34;product_route&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">setCount</span><span style="color:#f92672">(</span>3<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">setIntervalSec</span><span style="color:#f92672">(</span>1<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>	rules<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> GatewayFlowRule<span style="color:#f92672">(</span><span style="color:#e6db74">&#34;order_api&#34;</span><span style="color:#f92672">).</span>
</span></span><span style="display:flex;"><span>                setCount<span style="color:#f92672">(</span>1<span style="color:#f92672">).</span>
</span></span><span style="display:flex;"><span>                setIntervalSec<span style="color:#f92672">(</span>1<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>    GatewayRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">loadRules</span><span style="color:#f92672">(</span>rules<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>直接访问http://localhost:8091/api/hello 是不会发生限流的，访问http://localhost:9000/order-serv/api/hello 就会出现限流了.</p>
</li>
</ol>
<h1 id="第八章-链路追踪-sleuthzipkin">第八章 链路追踪 Sleuth&amp;Zipkin</h1>
<p>微服务架构是一个分布式架构，它按业务划分服务单元，一个分布式系统往往有很多个服务单元。由于服务单元数量众多，业务的复杂性，如果出现了错误和异常，很难去定位。主要体现在，一个请求可能需要调用很多个服务，而内部服务的调用复杂性，决定了问题难以定位。所以微服务架构中，必须实现分布式链路追踪，去跟进一个请求到底有哪些服务参与，参与的顺序又是怎样的，从而达到每个请求的步骤清晰可见，出了问题，很快定位。</p>
<p>分布式链路追踪（Distributed Tracing），就是将一次分布式请求还原成调用链路，进行日志记录，性能监控并将一次分布式请求的调用情况集中展示。比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等。</p>
<h2 id="81-常见的链路追踪技术">8.1 常见的链路追踪技术</h2>
<ul>
<li><strong>cat</strong> ：由大众点评开源，基于Java开发的实时应用监控平台，包括实时应用监控，业务监控 。 集成</li>
</ul>
<p>方案是通过代码埋点的方式来实现监控，比如： 拦截器，过滤器等。 对代码的侵入性很大，集成成本较高。风险较大。</p>
<ul>
<li>
<p><strong>zipkin</strong> ：由Twitter公司开源，开放源代码分布式的跟踪系统，用于收集服务的定时数据，以解决微服务架构中的延迟问题，包括：数据的收集、存储、查找和展现。该产品结合spring-cloud-sleuth使用较为简单， 集成很方便， 但是功能较简单。</p>
</li>
<li>
<p><strong>pinpoint</strong>： Pinpoint是韩国人开源的基于字节码注入的调用链分析，以及应用监控分析工具。特点</p>
</li>
</ul>
<p>是支持多种插件，UI功能强大，接入端无代码侵入。</p>
<ul>
<li><strong>skywalking</strong>：SkyWalking是本土开源的基于字节码注入的调用链分析，以及应用监控分析工具。特点是支持多</li>
</ul>
<p>种插件，UI功能较强，接入端无代码侵入。目前已加入Apache孵化器。</p>
<ul>
<li><strong>Sleuth</strong></li>
</ul>
<p>SpringCloud 提供的分布式系统中链路追踪解决方案。</p>
<h2 id="82-集成链路追踪组件sleuth">8.2 集成链路追踪组件Sleuth</h2>
<ol>
<li>
<p>在product-server和order-server中添加sleuth依赖</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;groupId&gt;</span>org.springframework.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-starter-sleuth<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span></code></pre></div></li>
<li>
<p>订单微服务调用商品微服务，这个流程中通过@Slfj打印日志.重启服务并访问测试</p>
<p>订单服务日志结果:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111501863.png" alt="image-20201101203506704"></strong></p>
<p>商品服务日志结果:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111502450.png" alt="image-20201101203619884"></strong></p>
</li>
</ol>
<h2 id="83-日志参数解释">8.3 日志参数解释</h2>
<p>日志格式:
[order-server,c323c72e7009c077,fba72d9c65745e60,false]</p>
<p>1、第一个值，spring.application.name的值</p>
<p>2、第二个值，c323c72e7009c077 ，sleuth生成的一个ID，叫Trace ID，用来标识一条请求链路，一条请求链路中包含一个Trace ID，多个Span ID</p>
<p>3、第三个值，fba72d9c65745e60、spanID 基本的工作单元，获取元数据，如发送一个http</p>
<p>4、第四个值：true，是否要将该信息输出到zipkin服务中来收集和展示。</p>
<h2 id="84-zipkinsleuth整合">8.4 Zipkin+Sleuth整合</h2>
<p>zipkin是Twitter基于google的分布式监控系统Dapper（论文）的开发源实现，zipkin用于跟踪分布式服务之间的应用数据链路，分析处理延时，帮助我们改进系统的性能和定位故障。</p>
<p>官网:https://zipkin.io/</p>
<ol>
<li>
<p>下载Zipkin的jar包，在官网可以下载.</p>
</li>
<li>
<p>通过命令行，输入下面的命令启动ZipKin Server</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>java -jar zipkin-server-2.22.1-exec.jar
</span></span></code></pre></div></li>
<li>
<p>通过浏览器访问 http://localhost:9411访问</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111502704.png" alt="image-20201102091554126"></strong></p>
</li>
<li>
<p>在订单微服务和商品微服务中添加zipkin依赖</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;groupId&gt;</span>org.springframework.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-starter-zipkin<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span></code></pre></div></li>
<li>
<p>在订单微服务和商品微服务中添加如下配置:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">zipkin</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">base-url</span>: <span style="color:#ae81ff">http://127.0.0.1:9411/</span> <span style="color:#75715e">#zipkin server的请求地址</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">discoveryClientEnabled</span>: <span style="color:#66d9ef">false</span> <span style="color:#75715e">#让nacos把它当成一个URL，而不要当做服务名</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">sleuth</span>: 
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">sampler</span>: 
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">probability</span>: <span style="color:#ae81ff">1.0</span> <span style="color:#75715e">#采样的百分比</span>
</span></span></code></pre></div></li>
<li>
<p>重启订单微服务和商品微服务,访问 http://localhost:8091/save?uid=1&amp;pid=1</p>
</li>
<li>
<p>访问zipkin的UI界面，观察效果</p>
</li>
</ol>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111502663.png" alt="image-20201102092213549"></strong></p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111502147.png" alt="image-20201102092245887"></strong></p>
<h1 id="第九章-配置中心-nacos-config">第九章 配置中心 Nacos Config</h1>
<h2 id="91-服务配置中心介绍">9.1 服务配置中心介绍</h2>
<p>首先我们来看一下,微服务架构下关于配置文件的一些问题：</p>
<ol>
<li>配置文件相对分散。在一个微服务架构下，配置文件会随着微服务的增多变的越来越多，而且分散</li>
</ol>
<p>在各个微服务中，不好统一配置和管理。</p>
<ol start="2">
<li>配置文件无法区分环境。微服务项目可能会有多个环境，例如：测试环境、预发布环境、生产环</li>
</ol>
<p>境。每一个环境所使用的配置理论上都是不同的，一旦需要修改，就需要我们去各个微服务下手动</p>
<p>维护，这比较困难。</p>
<ol start="3">
<li>配置文件无法实时更新。我们修改了配置文件之后，必须重新启动微服务才能使配置生效，这对一</li>
</ol>
<p>个正在运行的项目来说是非常不友好的。</p>
<p>基于上面这些问题，我们就需要<strong>配置中心</strong>的加入来解决这些问题。</p>
<p><strong>配置中心的思路是</strong>：</p>
<p>首先把项目中各种配置全部都放到一个集中的地方进行统一管理，并提供一套标准的接口。</p>
<p>当各个服务需要获取配置的时候，就来配置中心的接口拉取自己的配置。</p>
<p>当配置中心中的各种参数有更新的时候，也能通知到各个服务实时的过来同步最新的信息，使之动</p>
<p>态更新。</p>
<p>当加入了服务配置中心之后，我们的系统架构图会变成下面这样：</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111502162.png" alt="image-20201101222022206"></strong></p>
<h2 id="92-常见的服务配置中心">9.2 常见的服务配置中心</h2>
<ul>
<li><strong>Apollo</strong></li>
</ul>
<p>Apollo是由携程开源的分布式配置中心。特点有很多，比如：配置更新之后可以实时生效，支持灰</p>
<p>度发布功能，并且能对所有的配置进行版本管理、操作审计等功能，提供开放平台API。并且资料</p>
<p>也写的很详细。</p>
<ul>
<li><strong>Disconf</strong></li>
</ul>
<p>Disconf是由百度开源的分布式配置中心。它是基于Zookeeper来实现配置变更后实时通知和生效</p>
<p>的。</p>
<ul>
<li><strong>SpringCloud Confifig</strong></li>
</ul>
<p>这是Spring Cloud中带的配置中心组件。它和Spring是无缝集成，使用起来非常方便，并且它的配</p>
<p>置存储支持Git。不过它没有可视化的操作界面，配置的生效也不是实时的，需要重启或去刷新。</p>
<ul>
<li><strong>Nacos</strong></li>
</ul>
<p>这是SpingCloud alibaba技术栈中的一个组件，前面我们已经使用它做过服务注册中心。其实它也</p>
<p>集成了服务配置的功能，我们可以直接使用它作为服务配置中心。</p>
<h2 id="93-nacos-confifig入门">9.3 Nacos Confifig入门</h2>
<p>​	使用nacos作为配置中心，其实就是将nacos当做一个服务端，将各个微服务看成是客户端，我们</p>
<p>将各个微服务的配置文件统一存放在nacos上，然后各个微服务从nacos上拉取配置即可。</p>
<p>接下来我们以商品微服务为例，学习nacos confifig的使用。</p>
<ol>
<li>
<p>搭建nacos环境【使用现有的nacos环境即可】</p>
</li>
<li>
<p>在商品微服务中引入nacos的依赖</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;groupId&gt;</span>com.alibaba.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-starter-alibaba-nacos-config<span style="color:#f92672">&lt;/artifactId&gt;</span> 
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span></code></pre></div></li>
<li>
<p>在微服务中添加nacos config的配置</p>
<p><strong>注意</strong>:不能使用原来的<code>application.yml</code>作为配置文件，而是新建一个<code>bootstrap.yml</code>作为配置文件</p>
<pre tabindex="0"><code>配置文件优先级(由高到低):
bootstrap.properties -&gt; bootstrap.yml -&gt; application.properties -&gt; application.yml
</code></pre><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">application</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">product-service</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">nacos</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">config</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">server-addr</span>: <span style="color:#ae81ff">127.0.0.1</span>:<span style="color:#ae81ff">8848</span> <span style="color:#75715e">#nacos中心地址</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">file-extension</span>: <span style="color:#ae81ff">yaml</span> <span style="color:#75715e"># 配置文件格式</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">profiles</span>: 
</span></span><span style="display:flex;"><span>  	<span style="color:#f92672">active</span>: <span style="color:#ae81ff">dev</span> <span style="color:#75715e"># 环境标识</span>
</span></span></code></pre></div></li>
<li>
<p>在nacos中添加配置,然后把商品微服务application.yml配置复制到配置内容中.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111502479.png" alt="image-20201102093026806"></strong></p>
<p><img src="%E5%9B%BE%E7%89%87/image-20201102095324857.png" alt="image-20201102095324857"></p>
</li>
<li>
<p>注释本地的application.yam中的内容， 启动程序进行测试</p>
</li>
<li>
<p>如果依旧可以成功访问程序，说明我们nacos的配置中心功能已经实现</p>
</li>
</ol>
<h2 id="94-配置动态刷新">9.4 配置动态刷新</h2>
<p>​	在入门案例中，我们实现了配置的远程存放，但是此时如果修改了配置，我们的程序是无法读取到的，因此，我们需要开启配置的动态刷新功能.</p>
<ol>
<li>
<p>在nacos中的product-service-dev.yaml配置项中添加下面配置:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">appConfig</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">product2020</span>
</span></span></code></pre></div></li>
<li>
<p>在商品微服务中新增NacosConfigControlller.java</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RefreshScope</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">NacosConfigController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Value</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;${appConfig.name}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String appConfigName<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/nacosConfig1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">nacosConfig</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;远程信息:&#34;</span><span style="color:#f92672">+</span>appConfigName<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
</ol>
<h2 id="95-配置共享">9.5 配置共享</h2>
<p>当配置越来越多的时候，我们就发现有很多配置是重复的，这时候就考虑可不可以将公共配置文件提取出来，然后实现共享呢？当然是可以的。接下来我们就来探讨如何实现这一功能。</p>
<ul>
<li><strong>同一个微服务的不同环境之间共享配置</strong></li>
</ul>
<p>如果想在同一个微服务的不同环境之间实现配置共享，其实很简单。只需要提取一个以 spring.application.name 命名的配置文件，然后将其所有环境的公共配置放在里面即可。</p>
<ol>
<li>
<p>新建一个名为product-service.yaml配置存放商品微服务的公共配置,把之前的公共配置都存放进去.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111502137.png" alt="image-20201102101415390"></strong></p>
</li>
<li>
<p>新建一个名为product-service-test.yaml配置存放测试环境的配置</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111502824.png" alt="image-20201102102845484"></strong></p>
</li>
<li>
<p>新建一个名为product-service-dev.yaml配置存放测试环境的配置</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111502228.png" alt="image-20201102102132156"></strong></p>
</li>
<li>
<p>需要的配置信息具体如下:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111502930.png" alt="image-20201102101627185"></strong></p>
</li>
<li>
<p>在NacosConfigController.java中新增如下逻辑</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RefreshScope</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">NacosConfigController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Value</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;${appConfig.name}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String appConfigName<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Value</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;${env}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String env<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/nacosConfig1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">nacosConfig</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;远程信息:&#34;</span><span style="color:#f92672">+</span>appConfigName<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/nacosConfig2&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">nacosConfig2</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;公共配置:&#34;</span><span style="color:#f92672">+</span>appConfigName<span style="color:#f92672">+</span><span style="color:#e6db74">&#34;,环境配置信息:&#34;</span><span style="color:#f92672">+</span>env<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>通过修改环境，参看是否可以读取公共配置和环境独有配置</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111502924.png" alt="image-20201102102314702"></strong></p>
</li>
</ol>
<ul>
<li><strong>不同微服务中间共享配置</strong></li>
</ul>
<p>不同为服务之间实现配置共享的原理类似于文件引入，就是定义一个公共配置，然后在当前配置中引</p>
<p>入。</p>
<ol>
<li>在nacos中定义一个DataID为global-config.yaml的配置，用于所有微服务共享</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">globalConfig</span>: <span style="color:#ae81ff">global</span>
</span></span></code></pre></div><p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111502646.png" alt="image-20201102103412474"></strong></p>
<ol start="2">
<li>修改bootstrap.yaml</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">application</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">product-service</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">nacos</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">config</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">server-addr</span>: <span style="color:#ae81ff">127.0.0.1</span>:<span style="color:#ae81ff">8848</span> <span style="color:#75715e">#nacos中心地址</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">file-extension</span>: <span style="color:#ae81ff">yaml</span> <span style="color:#75715e"># 配置文件格式</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">shared-configs</span>:
</span></span><span style="display:flex;"><span>          - <span style="color:#f92672">data-id</span>: <span style="color:#ae81ff">global-config.yaml</span> <span style="color:#75715e"># 配置要引入的配置</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">refresh</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">profiles</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">active</span>: <span style="color:#ae81ff">test</span> <span style="color:#75715e"># 环境标识</span>
</span></span></code></pre></div><ol start="3">
<li>
<p>在NacosConfigController.java中新增一个方法</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RefreshScope</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">NacosConfigController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Value</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;${appConfig.name}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String appConfigName<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Value</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;${env}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String env<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Value</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;${globalConfig}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String globalConfig<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/nacosConfig1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">nacosConfig</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;远程信息:&#34;</span><span style="color:#f92672">+</span>appConfigName<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/nacosConfig2&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">nacosConfig2</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;公共配置:&#34;</span><span style="color:#f92672">+</span>appConfigName<span style="color:#f92672">+</span><span style="color:#e6db74">&#34;,环境配置信息:&#34;</span><span style="color:#f92672">+</span>env<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/nacosConfig3&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">nacosConfig3</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;全局配置:&#34;</span><span style="color:#f92672">+</span>globalConfig<span style="color:#f92672">+</span><span style="color:#e6db74">&#34;,公共配置:&#34;</span><span style="color:#f92672">+</span>appConfigName<span style="color:#f92672">+</span><span style="color:#e6db74">&#34;,环境配置信息:&#34;</span><span style="color:#f92672">+</span>env<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>重启服务并测试.</p>
</li>
</ol>

    <h4><a href="https://czh-dev.gitee.io/czh-blog.gitee.io/">Back to Home</a></h4>
  </div>

  <div class="span3 bs-docs-sidebar" style="position:fixed;right: 40px;top: 50px;">
    <h1>catalogue</h1>
    <ul class="nav nav-list bs-docs-sidenav">
      <div class="toc-div">
        <nav id="TableOfContents">
  <ul>
    <li><a href="#11-单体分布式集群">1.1 单体、分布式、集群</a></li>
    <li><a href="#12-系统架构演变">1.2 系统架构演变</a>
      <ul>
        <li><a href="#121-单体应用架构">1.2.1 单体应用架构</a></li>
        <li><a href="#122-垂直应用架构">1.2.2 垂直应用架构</a></li>
        <li><a href="#123-分布式架构">1.2.3 分布式架构</a></li>
        <li><a href="#124-soa架构">1.2.4 SOA架构</a></li>
        <li><a href="#125-微服务架构">1.2.5 微服务架构</a></li>
      </ul>
    </li>
    <li><a href="#13-微服务架构介绍">1.3 微服务架构介绍</a></li>
    <li><a href="#14-springcloud介绍">1.4 SpringCloud介绍</a>
      <ul>
        <li><a href="#141-springboot和springcloud有啥关系">1.4.1 SpringBoot和SpringCloud有啥关系?</a></li>
        <li><a href="#142-springcloud版本名称">1.4.2 SpringCloud版本名称?</a></li>
        <li><a href="#143-为什么选择springcloud-alibaba">1.4.3 为什么选择SpringCloud Alibaba？</a></li>
      </ul>
    </li>
  </ul>

  <ul>
    <li><a href="#21-技术选型">2.1 技术选型</a></li>
    <li><a href="#22-模块设计">2.2 模块设计</a></li>
    <li><a href="#23-微服务调用">2.3 微服务调用</a></li>
    <li><a href="#24-版本说明">2.4 版本说明</a></li>
    <li><a href="#25-创建父工程">2.5 创建父工程</a></li>
    <li><a href="#26-创建商品微服务">2.6 创建商品微服务</a></li>
    <li><a href="#27-创建订单微服务">2.7 创建订单微服务</a></li>
    <li><a href="#28-服务间如何进行远程调用">2.8 服务间如何进行远程调用</a></li>
  </ul>

  <ul>
    <li><a href="#31-什么是服务治理">3.1 什么是服务治理</a></li>
    <li><a href="#32-常见注册中心">3.2 常见注册中心</a></li>
    <li><a href="#33-nacos-简介">3.3 Nacos 简介</a></li>
    <li><a href="#34-nacos实战入门">3.4 Nacos实战入门</a>
      <ul>
        <li><a href="#341-搭建nacos环境">3.4.1 搭建Nacos环境</a></li>
        <li><a href="#342-将商品服务注册到nacos">3.4.2 将商品服务注册到Nacos</a></li>
        <li><a href="#343-将订单服务注册到nacos">3.4.3 将订单服务注册到Nacos</a></li>
      </ul>
    </li>
  </ul>

  <ul>
    <li><a href="#41-什么是负载均衡">4.1 什么是负载均衡</a></li>
    <li><a href="#42-自定义负载均衡">4.2 自定义负载均衡</a></li>
    <li><a href="#43-基于ribbon实现负载均衡">4.3 基于Ribbon实现负载均衡</a></li>
  </ul>

  <ul>
    <li><a href="#51-什么是openfeign">5.1 什么是OpenFeign</a></li>
    <li><a href="#52-订单微服务集成feign">5.2 订单微服务集成Feign</a></li>
  </ul>

  <ul>
    <li><a href="#61-高并发带来的问题">6.1 高并发带来的问题</a></li>
    <li><a href="#62-服务器雪崩效应">6.2 服务器雪崩效应</a></li>
    <li><a href="#62-常见容错方案">6.2 常见容错方案</a></li>
    <li><a href="#63-常见的容错组件">6.3 常见的容错组件</a></li>
    <li><a href="#64-sentinel入门">6.4 Sentinel入门</a>
      <ul>
        <li><a href="#641-什么是sentinel">6.4.1 什么是Sentinel</a></li>
        <li><a href="#642-订单微服务集成sentinel">6.4.2 订单微服务集成Sentinel</a></li>
        <li><a href="#643-安装sentinel控制台">6.4.3 安装Sentinel控制台</a></li>
        <li><a href="#644-实现一个接口的限流">6.4.4 实现一个接口的限流</a></li>
        <li><a href="#645-sentinel容错的维度">6.4.5 Sentinel容错的维度</a></li>
        <li><a href="#646-sentinel规则种类">6.4.6 Sentinel规则种类</a></li>
      </ul>
    </li>
    <li><a href="#65-sentinel规则-流控">6.5 Sentinel规则-流控</a>
      <ul>
        <li><a href="#651-流控规则">6.5.1 流控规则</a></li>
        <li><a href="#652-流控模式">6.5.2 流控模式</a></li>
        <li><a href="#653-流控效果">6.5.3 流控效果</a></li>
      </ul>
    </li>
    <li><a href="#66-sentinel规则-降级">6.6 Sentinel规则-降级</a>
      <ul>
        <li><a href="#661-慢调用比例案例">6.6.1 慢调用比例案例</a></li>
        <li><a href="#662-异常比例案例">6.6.2 异常比例案例</a></li>
        <li><a href="#633-异常数案例">6.3.3 异常数案例</a></li>
      </ul>
    </li>
    <li><a href="#67-sentinel规则-热点">6.7 Sentinel规则-热点</a></li>
    <li><a href="#68-sentinel规则-授权">6.8 Sentinel规则-授权</a></li>
    <li><a href="#69-sentinel规则-系统规则">6.9 Sentinel规则-系统规则</a></li>
    <li><a href="#610--sentinel-自定义异常返回">6.10  Sentinel 自定义异常返回</a></li>
    <li><a href="#611-sentinelresource的使用">6.11 @SentinelResource的使用</a></li>
    <li><a href="#612-sentinel规则持久化">6.12 Sentinel规则持久化</a></li>
    <li><a href="#613-feign整合sentinel">6.13 Feign整合Sentinel</a></li>
  </ul>

  <ul>
    <li><a href="#71-常见网关介绍">7.1 常见网关介绍</a></li>
    <li><a href="#72-gateway简介">7.2 Gateway简介</a></li>
    <li><a href="#73-gateway快速入门">7.3 Gateway快速入门</a></li>
    <li><a href="#74-自定义路由规则">7.4 自定义路由规则</a></li>
    <li><a href="#75-gateway概念">7.5 Gateway概念</a></li>
    <li><a href="#76-过滤器filter">7.6 过滤器Filter</a>
      <ul>
        <li><a href="#761-局部路由过滤器">7.6.1 局部路由过滤器</a></li>
        <li><a href="#762-全局路由过滤器">7.6.2 全局路由过滤器</a></li>
      </ul>
    </li>
    <li><a href="#77-集成sentinel实现网关限流">7.7 集成Sentinel实现网关限流</a>
      <ul>
        <li><a href="#771-网关集成sentinel">7.7.1 网关集成Sentinel</a></li>
        <li><a href="#772-修改限流默认返回格式">7.7.2 修改限流默认返回格式</a></li>
        <li><a href="#773-自定义api分组">7.7.3 自定义API分组</a></li>
      </ul>
    </li>
  </ul>

  <ul>
    <li><a href="#81-常见的链路追踪技术">8.1 常见的链路追踪技术</a></li>
    <li><a href="#82-集成链路追踪组件sleuth">8.2 集成链路追踪组件Sleuth</a></li>
    <li><a href="#83-日志参数解释">8.3 日志参数解释</a></li>
    <li><a href="#84-zipkinsleuth整合">8.4 Zipkin+Sleuth整合</a></li>
  </ul>

  <ul>
    <li><a href="#91-服务配置中心介绍">9.1 服务配置中心介绍</a></li>
    <li><a href="#92-常见的服务配置中心">9.2 常见的服务配置中心</a></li>
    <li><a href="#93-nacos-confifig入门">9.3 Nacos Confifig入门</a></li>
    <li><a href="#94-配置动态刷新">9.4 配置动态刷新</a></li>
    <li><a href="#95-配置共享">9.5 配置共享</a></li>
  </ul>
</nav>
      </div>
    </ul>
  </div>

</div>
<script src="https://cdn.jsdelivr.net/npm/gumshoejs@5.1.2/dist/gumshoe.min.js"></script>
<script>
  var spy = new Gumshoe('#TableOfContents a', {
    nested: true,
    nestedClass: 'active'
  });
</script>
<style>
   
  #TableOfContents li,
  #TableOfContents ul {
    list-style-type: none;
  }

  #TableOfContents ul {
    padding-left: 0px;
  }

  #TableOfContents li>a {
    display: block;
    padding: 4px 20px;
    font-size: 95%;
    color: #000000;
  }

  #TableOfContents li>a:hover,
  #TableOfContents li>a:focus {
    padding-left: 19px;
    color: #3A6bA5;
    text-decoration: none;
    background-color: transparent;
    border-left: 1px solid #3A6bA5;
  }

  #TableOfContents li.active>a,
  #TableOfContents li.active>a:hover,
  #TableOfContents li.active>a:focus {
    padding-left: 18px;
    font-weight: bold;
    color: #3A6bA5;
    background-color: transparent;
    border-left: 2px solid #3A6bA5;
  }

   
  #TableOfContents li>ul {
    padding-bottom: 10px;
  }

  #TableOfContents li li>a {
    padding-top: 1px;
    padding-bottom: 1px;
    padding-left: 30px;
    font-size: 14px;
    font-weight: normal;
  }

  #TableOfContents li li>a:hover,
  #TableOfContents li li>a:focus {
    padding-left: 29px;
  }

  #TableOfContents li li.active>a,
  #TableOfContents li li.active>a:hover,
  #TableOfContents li li.active>a:focus {
    padding-left: 28px;
    font-weight: 500;
  }

  #TableOfContents .nav-link.active+ul {
    display: block;
  }

  #TableOfContents li>ul {
    display: none;
  }

  #TableOfContents li.active>ul {
    display: inherit;
  }

  .toc-div {
    position: -webkit-sticky;
     
    position: sticky;
     
    top: 20px;
  }
</style>


        </div><footer class="container">
    <hr class="soften">
    <p>
    <a href="https://space.bilibili.com/1799809923">Love eating fried pork ribs</a> | 

&copy; 
<a href="http://jmf-portfolio.netlify.com" target="_blank">
    JM Fergeau
</a>
<span id="thisyear">2023</span>

    | My site


        | Built on <a href="//gohugo.io" target="_blank">Hugo</a>

</p>
    <p class="text-center">
        <a href="https://facebook.com">Facebook</a> 
        <a href="https://twitter.com">Twitter</a> 
        <a href="https://linkedin.com">Linkedin</a> 
        <a href="https://github.com">GitHub</a> 
        <a href="https://gitlab.com">GitLab</a>
    </p>
</footer>

</body><link rel="stylesheet" href="/czh-blog.gitee.io/css/bootstrap.css">
<link rel="stylesheet" href="/czh-blog.gitee.io/css/bootstrap-responsive.css">
<link rel="stylesheet" href="/czh-blog.gitee.io/css/style.css">

<script src="/czh-blog.gitee.io/js/jquery.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-386.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-transition.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-alert.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-modal.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-dropdown.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-scrollspy.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-tab.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-tooltip.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-popover.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-button.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-collapse.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-carousel.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-typeahead.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-affix.js"></script>
<script>
    _386 = { 
        fastLoad: false ,
        onePass: false , 
        speedFactor: 1 
    };

    
    function ThisYear() {
        document.getElementById('thisyear').innerHTML = new Date().getFullYear();
    };
</script>
</html>
